<!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;">&#160;</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;
&#160;
&#160;
<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;
&#160;
&#160;
<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;
&#160;
&#160;
<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}.
 *
 * &lt;br /&gt;
 * &lt;br /&gt;
 *
 * The default location of the local module repository is located on the filesystem at
 * &lt;code&gt;$USER_HOME/.jboss/modules/repo&lt;/code&gt;, 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 &lt;a href="mailto:alr@jboss.org"&gt;Andrew Lee Rubinger&lt;/a&gt;
 */</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>
&#160;
&#160;
&#160;&#160;&#160; <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());
&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; + File.separatorChar + <font color="red">"repo"</font>;
&#160;&#160;&#160; <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>));
&#160;&#160;&#160; <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);
&#160;&#160;&#160; <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>;
&#160;&#160;&#160; <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>;
&#160;&#160;&#160; <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>;
&#160;&#160;&#160; <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>;
&#160;&#160;&#160; <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>;
&#160;&#160;&#160; <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>;
&#160;&#160;&#160; <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>;
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Root of the (possibly) remote repository from which to fetch modules
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <font color="navy"><b>private</b></font> <font color="navy"><b>final</b></font> URL rootUrl;
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Root of the local module repository
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <font color="navy"><b>final</b></font> File localRepoRoot;
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Delegate used to load modules from the local module repository
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <font color="navy"><b>private</b></font> <font color="navy"><b>final</b></font> LocalModuleLoader localDelegate;
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Creates a new instance using the specified root {@link URL} for the backing repository and the specified
&#160;&#160;&#160;&#160; * {@link File} root for the local repository. Both arguments are required, and the local repository root must both
&#160;&#160;&#160;&#160; * exist and be a directory, else {@link IllegalArgumentException} will be raised.
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @param rootUrl
&#160;&#160;&#160;&#160; * @param localRepoRoot
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (rootUrl == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> IllegalArgumentException(<font color="red">"Root URL must be specified"</font>);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (localRepoRoot == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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>);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (!localRepoRoot.exists()) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (!localRepoRoot.isDirectory()) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.localRepoRoot = localRepoRoot;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.rootUrl = rootUrl;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; 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>);
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Creates a new {@link RepositoryModuleLoader} instance using the specified root URL from which to fetch modules
&#160;&#160;&#160;&#160; * and the specified local repository root to cache downloaded modules.
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @param rootUrl
&#160;&#160;&#160;&#160; * @param localRepoRoot
&#160;&#160;&#160;&#160; * @return
&#160;&#160;&#160;&#160; * @throws IllegalArgumentException
&#160;&#160;&#160;&#160; *&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; If either argument is not specified, or if the local repository root does not exist or is not a
&#160;&#160;&#160;&#160; *&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; directory
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <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)
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>throws</b></font> IllegalArgumentException <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> <font color="navy"><b>new</b></font> RepositoryModuleLoader(rootUrl, localRepoRoot);
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Creates a new {@link RepositoryModuleLoader} instance using the specified root URL from which to fetch modules
&#160;&#160;&#160;&#160; * and the default local repository root (USER_HOME_DIR/.jboss/modules/repo) to cache downloaded modules.
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @param rootUrl
&#160;&#160;&#160;&#160; * @return
&#160;&#160;&#160;&#160; * @throws IllegalArgumentException
&#160;&#160;&#160;&#160; *&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; If the root {@link URL} is not specified
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Create default local repo if it doesn't exist</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (!DEFAULT_LOCAL_REPO.exists() &amp;&amp; !DEFAULT_LOCAL_REPO.mkdirs()) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + DEFAULT_LOCAL_REPO.getAbsolutePath());
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> <font color="navy"><b>new</b></font> RepositoryModuleLoader(rootUrl, DEFAULT_LOCAL_REPO);
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * {@inheritDoc}
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @see org.jboss.modules.ModuleLoader#toString()
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; @Override
&#160;&#160;&#160; <font color="navy"><b>public</b></font> String toString() <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> RepositoryModuleLoader.class.getSimpleName() + <font color="red">" with root URL: "</font> + this.rootUrl
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + <font color="red">" and using local module repository root "</font> + localRepoRoot.getAbsolutePath();
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * {@inheritDoc}
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @see org.jboss.modules.ModuleLoader#preloadModule(org.jboss.modules.ModuleIdentifier)
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; @Override
&#160;&#160;&#160; <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>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; Module module;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; module = ModuleLoader.preloadModule(identifier, localDelegate);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> ModuleNotFoundException mnfe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Fetch and try again</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.fetchModuleAssets(identifier);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; module = ModuleLoader.preloadModule(identifier, localDelegate);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Return</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> module;
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * {@inheritDoc}
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @see org.jboss.modules.ModuleLoader#findModule(org.jboss.modules.ModuleIdentifier)
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; @Override
&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// We never load the module, the local delegate does via preloadModule</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// FIXME This mechanism really breaks the stated purpose of the SPI, raise the issue to DML</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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>);
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Obtains all module resources for the given (required) {@link ModuleIdentifier}. Will recurse to obtain dependent
&#160;&#160;&#160;&#160; * module assets as well.
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @param moduleIdentifier
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <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>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>assert</b></font> moduleIdentifier != <font color="navy"><b>null</b></font> : <font color="red">"Module identifier is required"</font>;
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Fetch the module.xml into the local modules repo</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> String relativePath = toHttpPathString(moduleIdentifier);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> File localRepoModuleRoot = <font color="navy"><b>new</b></font> File(localRepoRoot, toLocalDiskPathString(moduleIdentifier));
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> File localModulesFile;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; localModulesFile = this.downloadToLocalRepository(relativePath, NAME_MODULES_DESCRIPTOR,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; localRepoModuleRoot);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Parse out the name of the resource root and any dependencies</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; String resourceRootPath = <font color="navy"><b>null</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> Set&lt;String&gt; dependencies = <font color="navy"><b>new</b></font> HashSet&lt;String&gt;();
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> XMLStreamReader reader;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; reader = XMLInputFactory.newInstance().createXMLStreamReader(<font color="navy"><b>new</b></font> FileInputStream(localModulesFile));
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; + localModulesFile.getAbsolutePath());
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> XMLStreamException xmlse) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(xmlse);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FactoryConfigurationError fce) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(fce);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>boolean</b></font> inDependenciesSection = <font color="navy"><b>false</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; readerLoop: <font color="navy"><b>while</b></font> (reader.hasNext()) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> <font color="navy"><b>int</b></font> next = reader.next();
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>switch</b></font> (next) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>case</b></font> XMLStreamReader.START_ELEMENT:
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String elementName = reader.getLocalName();
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (ELEMENT_NAME_RESOURCE_ROOT.equals(elementName)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> <font color="navy"><b>int</b></font> numAttributes = reader.getAttributeCount();
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>for</b></font> (<font color="navy"><b>int</b></font> i = 0; i &lt; numAttributes; i++) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> String attribute = reader.getAttributeLocalName(i);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (ATTRIBUTE_NAME_PATH.equals(attribute)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; resourceRootPath = reader.getAttributeValue(i);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>continue</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (ELEMENT_NAME_DEPENDENCIES.equals(elementName)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; inDependenciesSection = <font color="navy"><b>true</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>continue</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (ELEMENT_NAME_MODULE.equals(elementName) &amp;&amp; inDependenciesSection) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> <font color="navy"><b>int</b></font> numAttributes = reader.getAttributeCount();
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>for</b></font> (<font color="navy"><b>int</b></font> i = 0; i &lt; numAttributes; i++) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> String attribute = reader.getAttributeLocalName(i);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (ATTRIBUTE_NAME_NAME.equals(attribute)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dependencies.add(reader.getAttributeValue(i));
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>continue</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>case</b></font> XMLStreamReader.END_ELEMENT:
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; elementName = reader.getLocalName();
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (ELEMENT_NAME_DEPENDENCIES.equals(elementName)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>break</b></font> readerLoop;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> XMLStreamException xmlse) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (resourceRootPath == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Could be to system path, so we're done here</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Get all dependencies recursively</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>for</b></font> (<font color="navy"><b>final</b></font> String dependency : dependencies) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> ModuleIdentifier moduleId = ModuleIdentifier.fromString(dependency);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.fetchModuleAssets(moduleId);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Download the resource root</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.downloadToLocalRepository(relativePath, resourceRootPath, localRepoModuleRoot);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Download the index file</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> String indexFileName = resourceRootPath + SUFFIX_INDEX;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.downloadToLocalRepository(relativePath, indexFileName, localRepoModuleRoot);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Ignore, must be no index</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (log.isLoggable(Level.FINEST)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; log.finest(<font color="red">"No index file found: "</font> + indexFileName + <font color="red">"; skipping."</font>);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <font color="darkgreen">/**
&#160;&#160;&#160;&#160; * Performs the download of the remote file name located in the relative remote path to the specified parent
&#160;&#160;&#160;&#160; * directory. All arguments are required.
&#160;&#160;&#160;&#160; *
&#160;&#160;&#160;&#160; * @param relativeRemotePath
&#160;&#160;&#160;&#160; * @param remoteFileName
&#160;&#160;&#160;&#160; * @param parentDir
&#160;&#160;&#160;&#160; * @return
&#160;&#160;&#160;&#160; * @throws FileNotFoundException
&#160;&#160;&#160;&#160; *&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; If the requested resource could not be found in the remote path with the remote file name
&#160;&#160;&#160;&#160; */</font>
&#160;&#160;&#160; <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,
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> File parentDir) <font color="navy"><b>throws</b></font> FileNotFoundException <font color="navy">{</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>assert</b></font> relativeRemotePath != <font color="navy"><b>null</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>assert</b></font> remoteFileName != <font color="navy"><b>null</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>assert</b></font> parentDir != <font color="navy"><b>null</b></font>;
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> URL relativePathURL;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> URL fullURL;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; relativePathURL = <font color="navy"><b>new</b></font> URL(rootUrl, relativeRemotePath);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; fullURL = <font color="navy"><b>new</b></font> URL(relativePathURL, remoteFileName);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> MalformedURLException murle) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(murle);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> File targetFile = <font color="navy"><b>new</b></font> File(parentDir, remoteFileName);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> InputStream in;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; log.info(<font color="red">"Writing: "</font> + fullURL + <font color="red">" as "</font> + targetFile);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; in = fullURL.openStream();
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> IOException ioe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (in == <font color="navy"><b>null</b></font>) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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());
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (!parentDir.exists() &amp;&amp; !parentDir.mkdirs()) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; OutputStream out = <font color="navy"><b>null</b></font>;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out = <font color="navy"><b>new</b></font> FileOutputStream(targetFile);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> FileNotFoundException fnfe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(fnfe);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// source is</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>int</b></font> readBytes = 0;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>while</b></font> ((readBytes = in.read(buffer)) != -1) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.write(buffer, 0, readBytes);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Only way to show incremental progress without flooding the log with unnecessary lines is to</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// write straight to console</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.print(<font color="navy">'.'</font>);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println();
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> IOException ioe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>throw</b></font> <font color="navy"><b>new</b></font> RuntimeException(ioe);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>finally</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>try</b></font> <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (out != <font color="navy"><b>null</b></font>) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; out.close();
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>if</b></font> (log.isLoggable(Level.INFO)) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; log.info(<font color="red">"Wrote "</font> + targetFile.getAbsolutePath());
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font> <font color="navy"><b>catch</b></font> (<font color="navy"><b>final</b></font> IOException ioe) <font color="navy">{</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Swallow</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="darkgreen">// Return</font>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> targetFile;
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> toPathString(moduleIdentifier, <font color="navy">'/'</font>);
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> toPathString(moduleIdentifier, File.separatorChar);
&#160;&#160;&#160; <font color="navy">}</font>
&#160;
&#160;
&#160;&#160;&#160; <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>
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>final</b></font> StringBuilder builder = <font color="navy"><b>new</b></font> StringBuilder(40);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; builder.append(moduleIdentifier.getName().replace(<font color="navy">'.'</font>, replacementChar));
&#160;&#160;&#160;&#160;&#160;&#160;&#160; builder.append(replacementChar).append(moduleIdentifier.getSlot());
&#160;&#160;&#160;&#160;&#160;&#160;&#160; builder.append(replacementChar);
&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="navy"><b>return</b></font> builder.toString();
&#160;&#160;&#160; <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>