<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<body link="#355491" alink="#4262a1" vlink="#355491" style="background: #e2e2e2; margin: 0; padding: 20px;">
<div>
        <table cellpadding="0" bgcolor="#FFFFFF" border="0" cellspacing="0" style="border: 1px solid #dadada; margin-bottom: 30px; width: 100%; -moz-border-radius: 6px; -webkit-border-radius: 6px;">
                <tbody>
                        <tr>
                                <td>
                                        <table border="0" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF" style="border: solid 2px #ccc; background: #dadada; width: 100%; -moz-border-radius: 6px; -webkit-border-radius: 6px;">
                                                <tbody>
                                                        <tr>
                                                                <td bgcolor="#000000" valign="middle" height="58px" style="border-bottom: 1px solid #ccc; padding: 20px; -moz-border-radius-topleft: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 5px; -webkit-border-top-left-radius: 5px;">
                                                                        <h1 style="color: #333333; font: bold 22px Arial, Helvetica, sans-serif; margin: 0; display: block !important;">
                                                                        <!-- To have a header image/logo replace the name below with your img tag -->
                                                                        <!-- Email clients will render the images when the message is read so any image -->
                                                                        <!-- must be made available on a public server, so that all recipients can load the image. -->
                                                                        <a href="https://community.jboss.org/index.jspa" style="text-decoration: none; color: #E1E1E1">JBoss Community</a></h1>
                                                                </td>
                                                        </tr>
                                                        <tr>
                                                                <td bgcolor="#FFFFFF" style="font: normal 12px Arial, Helvetica, sans-serif; color:#333333; padding: 20px; -moz-border-radius-bottomleft: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px;"><h3 style="margin: 10px 0 5px; font-size: 17px; font-weight: normal;">
Re: jboss-modules: Module Repository SPI and Extensibility
</h3>
<span style="margin-bottom: 10px;">
created by <a href="https://community.jboss.org/people/ALRubinger">Andrew Rubinger</a> in <i>JBoss AS 7 Development</i> - <a href="https://community.jboss.org/message/772249#772249">View the full discussion</a>
</span>
<hr style="margin: 20px 0; border: none; background-color: #dadada; height: 1px;">
<div class="jive-rendered-content"><p>And Randall, just to be complete, the RepositoryModuleLoader I've been playing with looks a bit like:</p><p style="min-height: 8pt; height: 8pt; padding: 0px;"> </p><pre class="jive-pre"><code class="jive-code jive-java"><font color="darkgreen">/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/</font>
<font color="navy"><b>package</b></font> org.jboss.modules;
 
 
<font color="navy"><b>import</b></font> java.io.File;
<font color="navy"><b>import</b></font> java.io.FileInputStream;
<font color="navy"><b>import</b></font> java.io.FileNotFoundException;
<font color="navy"><b>import</b></font> java.io.FileOutputStream;
<font color="navy"><b>import</b></font> java.io.IOException;
<font color="navy"><b>import</b></font> java.io.InputStream;
<font color="navy"><b>import</b></font> java.io.OutputStream;
<font color="navy"><b>import</b></font> java.net.MalformedURLException;
<font color="navy"><b>import</b></font> java.net.URL;
<font color="navy"><b>import</b></font> java.util.HashSet;
<font color="navy"><b>import</b></font> java.util.Set;
<font color="navy"><b>import</b></font> java.util.logging.Level;
<font color="navy"><b>import</b></font> java.util.logging.Logger;
 
 
<font color="navy"><b>import</b></font> javax.xml.stream.FactoryConfigurationError;
<font color="navy"><b>import</b></font> javax.xml.stream.XMLInputFactory;
<font color="navy"><b>import</b></font> javax.xml.stream.XMLStreamException;
<font color="navy"><b>import</b></font> javax.xml.stream.XMLStreamReader;
 
 
<font color="darkgreen">/**
* {@link ModuleLoader} implementation which loads from a local module repository. If no matching module is found
* locally, an attempt will be made to resolve module resources from a (possibly remote) repository accessible via a
* root {@link URL}.
*
* <br />
* <br />
*
* The default location of the local module repository is located on the filesystem at
* <code>$USER_HOME/.jboss/modules/repo</code>, unless overridden by explicitly-providing a location via
* {@link RepositoryModuleLoader#create(URL, File)}. New {@link RepositoryModuleLoader} instances with the default local
* repository may be created using {@link RepositoryModuleLoader#create(URL)}.
*
* @author <a href="mailto:alr@jboss.org">Andrew Lee Rubinger</a>
*/</font>
<font color="navy"><b>public</b></font> <font color="navy"><b>final</b></font> <font color="navy"><b>class</b></font> RepositoryModuleLoader <font color="navy"><b>extends</b></font> ModuleLoader <font color="navy">{</font>
 
 
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> Logger log = Logger.getLogger(RepositoryModuleLoader.class.getName());
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String DEFAULT_NAME_REPOSITORY = <font color="red">".jboss"</font> + File.separatorChar + <font color="red">"modules"</font>
        + File.separatorChar + <font color="red">"repo"</font>;
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> File USER_HOME_DIR = <font color="navy"><b>new</b></font> File(SecurityActions.getSystemProperty(<font color="red">"user.home"</font>));
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> File DEFAULT_LOCAL_REPO = <font color="navy"><b>new</b></font> File(USER_HOME_DIR, DEFAULT_NAME_REPOSITORY);
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String NAME_MODULES_DESCRIPTOR = <font color="red">"module.xml"</font>;
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String ELEMENT_NAME_RESOURCE_ROOT = <font color="red">"resource-root"</font>;
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String ELEMENT_NAME_DEPENDENCIES = <font color="red">"dependencies"</font>;
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String ELEMENT_NAME_MODULE = <font color="red">"module"</font>;
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String ATTRIBUTE_NAME_PATH = <font color="red">"path"</font>;
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String ATTRIBUTE_NAME_NAME = <font color="red">"name"</font>;
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> <font color="navy"><b>final</b></font> String SUFFIX_INDEX = <font color="red">".index"</font>;
 
 
    <font color="darkgreen">/**
     * Root of the (possibly) remote repository from which to fetch modules
     */</font>
    <font color="navy"><b>private</b></font> <font color="navy"><b>final</b></font> URL rootUrl;
 
 
    <font color="darkgreen">/**
     * Root of the local module repository
     */</font>
    <font color="navy"><b>final</b></font> File localRepoRoot;
 
 
    <font color="darkgreen">/**
     * Delegate used to load modules from the local module repository
     */</font>
    <font color="navy"><b>private</b></font> <font color="navy"><b>final</b></font> LocalModuleLoader localDelegate;
 
 
    <font color="darkgreen">/**
     * Creates a new instance using the specified root {@link URL} for the backing repository and the specified
     * {@link File} root for the local repository. Both arguments are required, and the local repository root must both
     * exist and be a directory, else {@link IllegalArgumentException} will be raised.
     *
     * @param rootUrl
     * @param localRepoRoot
     */</font>
    <font color="navy"><b>private</b></font> RepositoryModuleLoader(<font color="navy"><b>final</b></font> URL rootUrl, <font color="navy"><b>final</b></font> File localRepoRoot) <font color="navy"><b>throws</b></font> IllegalArgumentException <font color="navy">{</font>
        <font color="navy"><b>if</b></font> (rootUrl == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> IllegalArgumentException(<font color="red">"Root URL must be specified"</font>);
        <font color="navy">}</font>
        <font color="navy"><b>if</b></font> (localRepoRoot == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> IllegalArgumentException(<font color="red">"Local Repository Root must be specified"</font>);
        <font color="navy">}</font>
        <font color="navy"><b>if</b></font> (!localRepoRoot.exists()) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> IllegalArgumentException(<font color="red">"Local Repository Root must exist: "</font> + localRepoRoot);
        <font color="navy">}</font>
        <font color="navy"><b>if</b></font> (!localRepoRoot.isDirectory()) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> IllegalArgumentException(<font color="red">"Local Repository Root must be a directory: "</font> + localRepoRoot);
        <font color="navy">}</font>
        this.localRepoRoot = localRepoRoot;
        this.rootUrl = rootUrl;
        this.localDelegate = <font color="navy"><b>new</b></font> LocalModuleLoader(<font color="navy"><b>new</b></font> File[] <font color="navy">{</font> localRepoRoot.getAbsoluteFile() <font color="navy">}</font>);
    <font color="navy">}</font>
 
 
    <font color="darkgreen">/**
     * Creates a new {@link RepositoryModuleLoader} instance using the specified root URL from which to fetch modules
     * and the specified local repository root to cache downloaded modules.
     *
     * @param rootUrl
     * @param localRepoRoot
     * @return
     * @throws IllegalArgumentException
     *             If either argument is not specified, or if the local repository root does not exist or is not a
     *             directory
     */</font>
    <font color="navy"><b>public</b></font> <font color="navy"><b>static</b></font> RepositoryModuleLoader create(<font color="navy"><b>final</b></font> URL rootUrl, <font color="navy"><b>final</b></font> File localRepoRoot)
        <font color="navy"><b>throws</b></font> IllegalArgumentException <font color="navy">{</font>
        <font color="navy"><b>return</b></font> <font color="navy"><b>new</b></font> RepositoryModuleLoader(rootUrl, localRepoRoot);
    <font color="navy">}</font>
 
 
    <font color="darkgreen">/**
     * Creates a new {@link RepositoryModuleLoader} instance using the specified root URL from which to fetch modules
     * and the default local repository root (USER_HOME_DIR/.jboss/modules/repo) to cache downloaded modules.
     *
     * @param rootUrl
     * @return
     * @throws IllegalArgumentException
     *             If the root {@link URL} is not specified
     */</font>
    <font color="navy"><b>public</b></font> <font color="navy"><b>static</b></font> RepositoryModuleLoader create(<font color="navy"><b>final</b></font> URL rootUrl) <font color="navy"><b>throws</b></font> IllegalArgumentException <font color="navy">{</font>
        <font color="darkgreen">// Create default local repo if it doesn't exist</font>
        <font color="navy"><b>if</b></font> (!DEFAULT_LOCAL_REPO.exists() && !DEFAULT_LOCAL_REPO.mkdirs()) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(<font color="red">"Could not create default local repository: "</font>
                + DEFAULT_LOCAL_REPO.getAbsolutePath());
 
 
        <font color="navy">}</font>
        <font color="navy"><b>return</b></font> <font color="navy"><b>new</b></font> RepositoryModuleLoader(rootUrl, DEFAULT_LOCAL_REPO);
    <font color="navy">}</font>
 
 
    <font color="darkgreen">/**
     * {@inheritDoc}
     *
     * @see org.jboss.modules.ModuleLoader#toString()
     */</font>
    @Override
    <font color="navy"><b>public</b></font> String toString() <font color="navy">{</font>
        <font color="navy"><b>return</b></font> RepositoryModuleLoader.class.getSimpleName() + <font color="red">" with root URL: "</font> + this.rootUrl
            + <font color="red">" and using local module repository root "</font> + localRepoRoot.getAbsolutePath();
    <font color="navy">}</font>
 
 
    <font color="darkgreen">/**
     * {@inheritDoc}
     *
     * @see org.jboss.modules.ModuleLoader#preloadModule(org.jboss.modules.ModuleIdentifier)
     */</font>
    @Override
    <font color="navy"><b>protected</b></font> Module preloadModule(<font color="navy"><b>final</b></font> ModuleIdentifier identifier) <font color="navy"><b>throws</b></font> ModuleLoadException <font color="navy">{</font>
 
 
        Module module;
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            module = ModuleLoader.preloadModule(identifier, localDelegate);
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> ModuleNotFoundException mnfe) <font color="navy">{</font>
            <font color="darkgreen">// Fetch and try again</font>
            this.fetchModuleAssets(identifier);
            module = ModuleLoader.preloadModule(identifier, localDelegate);
        <font color="navy">}</font>
 
 
        <font color="darkgreen">// Return</font>
        <font color="navy"><b>return</b></font> module;
    <font color="navy">}</font>
 
 
    <font color="darkgreen">/**
     * {@inheritDoc}
     *
     * @see org.jboss.modules.ModuleLoader#findModule(org.jboss.modules.ModuleIdentifier)
     */</font>
    @Override
    <font color="navy"><b>protected</b></font> ModuleSpec findModule(<font color="navy"><b>final</b></font> ModuleIdentifier moduleIdentifier) <font color="navy"><b>throws</b></font> ModuleLoadException <font color="navy">{</font>
        <font color="darkgreen">// We never load the module, the local delegate does via preloadModule</font>
        <font color="darkgreen">// FIXME This mechanism really breaks the stated purpose of the SPI, raise the issue to DML</font>
        <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> UnsupportedOperationException(<font color="red">"Should never be reached, we use a delegate loader"</font>);
    <font color="navy">}</font>
 
 
    <font color="darkgreen">/**
     * Obtains all module resources for the given (required) {@link ModuleIdentifier}. Will recurse to obtain dependent
     * module assets as well.
     *
     * @param moduleIdentifier
     */</font>
    <font color="navy"><b>private</b></font> <font color="navy"><b>void</b></font> fetchModuleAssets(<font color="navy"><b>final</b></font> ModuleIdentifier moduleIdentifier) <font color="navy">{</font>
 
 
        <font color="navy"><b>assert</b></font> moduleIdentifier != <font color="navy"><b>null</b></font> : <font color="red">"Module identifier is required"</font>;
 
 
        <font color="darkgreen">// Fetch the module.xml into the local modules repo</font>
        <font color="navy"><b>final</b></font> String relativePath = toHttpPathString(moduleIdentifier);
        <font color="navy"><b>final</b></font> File localRepoModuleRoot = <font color="navy"><b>new</b></font> File(localRepoRoot, toLocalDiskPathString(moduleIdentifier));
        <font color="navy"><b>final</b></font> File localModulesFile;
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            localModulesFile = this.downloadToLocalRepository(relativePath, NAME_MODULES_DESCRIPTOR,
                localRepoModuleRoot);
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(<font color="red">"Could not find "</font> + NAME_MODULES_DESCRIPTOR, fnfe);
        <font color="navy">}</font>
 
 
        <font color="darkgreen">// Parse out the name of the resource root and any dependencies</font>
        String resourceRootPath = <font color="navy"><b>null</b></font>;
        <font color="navy"><b>final</b></font> Set<String> dependencies = <font color="navy"><b>new</b></font> HashSet<String>();
        <font color="navy"><b>final</b></font> XMLStreamReader reader;
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            reader = XMLInputFactory.newInstance().createXMLStreamReader(<font color="navy"><b>new</b></font> FileInputStream(localModulesFile));
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(<font color="red">"Could not find the file we've just written: "</font>
                + localModulesFile.getAbsolutePath());
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> XMLStreamException xmlse) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(xmlse);
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FactoryConfigurationError fce) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(fce);
        <font color="navy">}</font>
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            <font color="navy"><b>boolean</b></font> inDependenciesSection = <font color="navy"><b>false</b></font>;
            readerLoop: <font color="navy"><b>while</b></font> (reader.hasNext()) <font color="navy">{</font>
                <font color="navy"><b>final</b></font> <font color="navy"><b>int</b></font> next = reader.next();
                <font color="navy"><b>switch</b></font> (next) <font color="navy">{</font>
                    <font color="navy"><b>case</b></font> XMLStreamReader.START_ELEMENT:
                        String elementName = reader.getLocalName();
                        <font color="navy"><b>if</b></font> (ELEMENT_NAME_RESOURCE_ROOT.equals(elementName)) <font color="navy">{</font>
                            <font color="navy"><b>final</b></font> <font color="navy"><b>int</b></font> numAttributes = reader.getAttributeCount();
                            <font color="navy"><b>for</b></font> (<font color="navy"><b>int</b></font> i = 0; i < numAttributes; i++) <font color="navy">{</font>
                                <font color="navy"><b>final</b></font> String attribute = reader.getAttributeLocalName(i);
                                <font color="navy"><b>if</b></font> (ATTRIBUTE_NAME_PATH.equals(attribute)) <font color="navy">{</font>
                                    resourceRootPath = reader.getAttributeValue(i);
                                <font color="navy">}</font>
                            <font color="navy">}</font>
                            <font color="navy"><b>continue</b></font>;
                        <font color="navy">}</font>
 
 
                        <font color="navy"><b>if</b></font> (ELEMENT_NAME_DEPENDENCIES.equals(elementName)) <font color="navy">{</font>
                            inDependenciesSection = <font color="navy"><b>true</b></font>;
                            <font color="navy"><b>continue</b></font>;
                        <font color="navy">}</font>
                        <font color="navy"><b>if</b></font> (ELEMENT_NAME_MODULE.equals(elementName) && inDependenciesSection) <font color="navy">{</font>
                            <font color="navy"><b>final</b></font> <font color="navy"><b>int</b></font> numAttributes = reader.getAttributeCount();
                            <font color="navy"><b>for</b></font> (<font color="navy"><b>int</b></font> i = 0; i < numAttributes; i++) <font color="navy">{</font>
                                <font color="navy"><b>final</b></font> String attribute = reader.getAttributeLocalName(i);
                                <font color="navy"><b>if</b></font> (ATTRIBUTE_NAME_NAME.equals(attribute)) <font color="navy">{</font>
                                    dependencies.add(reader.getAttributeValue(i));
                                <font color="navy">}</font>
                            <font color="navy">}</font>
                        <font color="navy">}</font>
                        <font color="navy"><b>continue</b></font>;
                    <font color="navy"><b>case</b></font> XMLStreamReader.END_ELEMENT:
                        elementName = reader.getLocalName();
                        <font color="navy"><b>if</b></font> (ELEMENT_NAME_DEPENDENCIES.equals(elementName)) <font color="navy">{</font>
                            <font color="navy"><b>break</b></font> readerLoop;
                        <font color="navy">}</font>
 
 
                <font color="navy">}</font>
            <font color="navy">}</font>
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> XMLStreamException xmlse) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(<font color="red">"Encountered error reading from "</font> + localModulesFile.getAbsolutePath(), xmlse);
        <font color="navy">}</font>
 
 
        <font color="navy"><b>if</b></font> (resourceRootPath == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
            <font color="darkgreen">// Could be to system path, so we're done here</font>
            <font color="navy"><b>return</b></font>;
        <font color="navy">}</font>
 
 
        <font color="darkgreen">// Get all dependencies recursively</font>
        <font color="navy"><b>for</b></font> (<font color="navy"><b>final</b></font> String dependency : dependencies) <font color="navy">{</font>
            <font color="navy"><b>final</b></font> ModuleIdentifier moduleId = ModuleIdentifier.fromString(dependency);
            this.fetchModuleAssets(moduleId);
        <font color="navy">}</font>
 
 
        <font color="darkgreen">// Download the resource root</font>
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            this.downloadToLocalRepository(relativePath, resourceRootPath, localRepoModuleRoot);
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(<font color="red">"Specified resource root could not be found: "</font> + resourceRootPath);
        <font color="navy">}</font>
        <font color="darkgreen">// Download the index file</font>
        <font color="navy"><b>final</b></font> String indexFileName = resourceRootPath + SUFFIX_INDEX;
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            this.downloadToLocalRepository(relativePath, indexFileName, localRepoModuleRoot);
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
            <font color="darkgreen">// Ignore, must be no index</font>
            <font color="navy"><b>if</b></font> (log.isLoggable(Level.FINEST)) <font color="navy">{</font>
                log.finest(<font color="red">"No index file found: "</font> + indexFileName + <font color="red">"; skipping."</font>);
            <font color="navy">}</font>
        <font color="navy">}</font>
    <font color="navy">}</font>
 
 
    <font color="darkgreen">/**
     * Performs the download of the remote file name located in the relative remote path to the specified parent
     * directory. All arguments are required.
     *
     * @param relativeRemotePath
     * @param remoteFileName
     * @param parentDir
     * @return
     * @throws FileNotFoundException
     *             If the requested resource could not be found in the remote path with the remote file name
     */</font>
    <font color="navy"><b>private</b></font> File downloadToLocalRepository(<font color="navy"><b>final</b></font> String relativeRemotePath, <font color="navy"><b>final</b></font> String remoteFileName,
        <font color="navy"><b>final</b></font> File parentDir) <font color="navy"><b>throws</b></font> FileNotFoundException <font color="navy">{</font>
 
 
        <font color="navy"><b>assert</b></font> relativeRemotePath != <font color="navy"><b>null</b></font>;
        <font color="navy"><b>assert</b></font> remoteFileName != <font color="navy"><b>null</b></font>;
        <font color="navy"><b>assert</b></font> parentDir != <font color="navy"><b>null</b></font>;
 
 
        <font color="navy"><b>final</b></font> URL relativePathURL;
        <font color="navy"><b>final</b></font> URL fullURL;
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            relativePathURL = <font color="navy"><b>new</b></font> URL(rootUrl, relativeRemotePath);
            fullURL = <font color="navy"><b>new</b></font> URL(relativePathURL, remoteFileName);
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> MalformedURLException murle) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(murle);
        <font color="navy">}</font>
        <font color="navy"><b>final</b></font> File targetFile = <font color="navy"><b>new</b></font> File(parentDir, remoteFileName);
        <font color="navy"><b>final</b></font> InputStream in;
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
                log.info(<font color="red">"Writing: "</font> + fullURL + <font color="red">" as "</font> + targetFile);
            <font color="navy">}</font>
            in = fullURL.openStream();
        <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> IOException ioe) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(<font color="red">"Could not get stream to "</font> + fullURL.toExternalForm(), ioe);
        <font color="navy">}</font>
        <font color="navy"><b>if</b></font> (in == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> FileNotFoundException(<font color="red">"Could not find requested file at URL: "</font> + fullURL.toExternalForm());
        <font color="navy">}</font>
        <font color="navy"><b>if</b></font> (!parentDir.exists() && !parentDir.mkdirs()) <font color="navy">{</font>
            <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> IllegalStateException(<font color="red">"Could not create parent directory: "</font> + parentDir);
        <font color="navy">}</font>
        OutputStream out = <font color="navy"><b>null</b></font>;
        <font color="navy"><b>try</b></font> <font color="navy">{</font>
            <font color="navy"><b>try</b></font> <font color="navy">{</font>
                out = <font color="navy"><b>new</b></font> FileOutputStream(targetFile);
            <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
                <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(fnfe);
            <font color="navy">}</font>
            <font color="navy"><b>final</b></font> <font color="navy"><b>byte</b></font>[] buffer = <font color="navy"><b>new</b></font> <font color="navy"><b>byte</b></font>[512]; <font color="darkgreen">// Relatively smaller buffer as we don't know how far away the</font>
                                                 <font color="darkgreen">// source is</font>
            <font color="navy"><b>try</b></font> <font color="navy">{</font>
                <font color="navy"><b>int</b></font> readBytes = 0;
                <font color="navy"><b>while</b></font> ((readBytes = in.read(buffer)) != -1) <font color="navy">{</font>
                    out.write(buffer, 0, readBytes);
                    <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
                        <font color="darkgreen">// Only way to show incremental progress without flooding the log with unnecessary lines is to</font>
                        <font color="darkgreen">// write straight to console</font>
                        System.out.print(<font color="navy">'.'</font>);
                    <font color="navy">}</font>
                <font color="navy">}</font>
                <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
                    System.out.println();
                <font color="navy">}</font>
            <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> IOException ioe) <font color="navy">{</font>
                <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(ioe);
            <font color="navy">}</font>
        <font color="navy">}</font> <font color="navy"><b>finally</b></font> <font color="navy">{</font>
            <font color="navy"><b>try</b></font> <font color="navy">{</font>
                <font color="navy"><b>if</b></font> (out != <font color="navy"><b>null</b></font>) <font color="navy">{</font>
                    out.close();
                    <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
                        log.info(<font color="red">"Wrote "</font> + targetFile.getAbsolutePath());
                    <font color="navy">}</font>
                <font color="navy">}</font>
            <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> IOException ioe) <font color="navy">{</font>
                <font color="darkgreen">// Swallow</font>
            <font color="navy">}</font>
        <font color="navy">}</font>
 
 
        <font color="darkgreen">// Return</font>
        <font color="navy"><b>return</b></font> targetFile;
    <font color="navy">}</font>
 
 
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> String toHttpPathString(<font color="navy"><b>final</b></font> ModuleIdentifier moduleIdentifier) <font color="navy">{</font>
        <font color="navy"><b>return</b></font> toPathString(moduleIdentifier, <font color="navy">'/'</font>);
    <font color="navy">}</font>
 
 
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> String toLocalDiskPathString(<font color="navy"><b>final</b></font> ModuleIdentifier moduleIdentifier) <font color="navy">{</font>
        <font color="navy"><b>return</b></font> toPathString(moduleIdentifier, File.separatorChar);
    <font color="navy">}</font>
 
 
    <font color="navy"><b>private</b></font> <font color="navy"><b>static</b></font> String toPathString(<font color="navy"><b>final</b></font> ModuleIdentifier moduleIdentifier, <font color="navy"><b>final</b></font> <font color="navy"><b>char</b></font> replacementChar) <font color="navy">{</font>
        <font color="navy"><b>final</b></font> StringBuilder builder = <font color="navy"><b>new</b></font> StringBuilder(40);
        builder.append(moduleIdentifier.getName().replace(<font color="navy">'.'</font>, replacementChar));
        builder.append(replacementChar).append(moduleIdentifier.getSlot());
        builder.append(replacementChar);
        <font color="navy"><b>return</b></font> builder.toString();
    <font color="navy">}</font>
<font color="navy">}</font>
</code></pre></div>
<div style="background-color: #f4f4f4; padding: 10px; margin-top: 20px;">
<p style="margin: 0;">Reply to this message by <a href="https://community.jboss.org/message/772249#772249">going to Community</a></p>
        <p style="margin: 0;">Start a new discussion in JBoss AS 7 Development at <a href="https://community.jboss.org/choose-container!input.jspa?contentType=1&containerType=14&container=2225">Community</a></p>
</div></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>