Author: bpoussin Date: 2013-01-05 03:50:34 +0100 (Sat, 05 Jan 2013) New Revision: 2460 Url: http://nuiton.org/projects/nuiton-utils/repository/revisions/2460 Log: utilsation de commons-vfs2 pour l'acces au ressource ce qui permet de supporter tout type de protocole et de format de compression Modified: trunk/nuiton-utils/pom.xml trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationUpdaterTest.java trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterNetworkTest.properties trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterTest.properties trunk/pom.xml Modified: trunk/nuiton-utils/pom.xml =================================================================== --- trunk/nuiton-utils/pom.xml 2013-01-04 15:51:26 UTC (rev 2459) +++ trunk/nuiton-utils/pom.xml 2013-01-05 02:50:34 UTC (rev 2460) @@ -44,6 +44,21 @@ </dependency> <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + </dependency> + + <dependency> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-vfs2</artifactId> + </dependency> + + <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </dependency> Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java =================================================================== --- trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java 2013-01-04 15:51:26 UTC (rev 2459) +++ trunk/nuiton-utils/src/main/java/org/nuiton/util/ApplicationUpdater.java 2013-01-05 02:50:34 UTC (rev 2460) @@ -5,11 +5,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.Proxy; -import java.net.SocketAddress; -import java.net.URL; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -21,6 +16,13 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs2.AllFileSelector; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileSystemManager; +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.VFS; +import org.apache.commons.vfs2.provider.http.HttpFileSystemConfigBuilder; /** * Permet de telecharger des mises a jour d'application. @@ -29,7 +31,7 @@ * information necessaire pour la recuperation de l'application. * * Si une nouvelle version de l'application existe, elle est alors telechargee - * et dezipper dans un repertoire specifique (elle ne remplace pas l'application + * et decompressee dans un repertoire specifique (elle ne remplace pas l'application * courante). * * Il est alors a la charge d'un script de mettre en place cette nouvelle application @@ -49,7 +51,8 @@ * * <h3>format du fichier de properties</h3> * [osName.][osArch.]appName.version=version de l'application - * [osName.][osArch.]appName.url=url du zip de la nouvelle version + * [osName.][osArch.]appName.url=url du fichier compresse de la nouvelle version + * (format <a href="http://commons.apache.org/vfs/filesystems.html">commons-vfs2</a>) * * appName est a remplacer par le nom de l'application. Il est possible * d'avoir plusieurs application dans le meme fichier ou plusieurs version @@ -57,13 +60,13 @@ * * osName et osArch sont toujours en minuscule * - * <h3>format des fichiers zip applicatif</h3> + * <h3>format des fichiers compresses</h3> * - * Le zip doit avec un repertoire racine qui contient l'ensemble de l'application + * Le fichier compresse doit avoir un repertoire racine qui contient l'ensemble de l'application * c-a-d que les fichiers ne doivent pas etre directement a la racine lorsqu'on - * dezippe le fichier. + * decompresse le fichier. * - * exemple de contenu de zip convenable + * exemple de contenu de fichier compresse convenable * <pre> * MonApp-0.3/Readme.txt * MonApp-0.3/License.txt @@ -150,8 +153,8 @@ * @param async if true, check is done in background mode * @param callback callback used to interact with updater, can be null */ - public void update(URL propertiesURL, File currentDir, File destDir, boolean async, ApplicationUpdaterCallback callback) { - Updater up = new Updater(config, propertiesURL, currentDir, destDir, callback); + public void update(String vfsPropertiesURL, File currentDir, File destDir, boolean async, ApplicationUpdaterCallback callback) { + Updater up = new Updater(config, vfsPropertiesURL, currentDir, destDir, callback); if (async) { Thread thread = new Thread(up, ApplicationUpdater.class.getSimpleName()); thread.start(); @@ -232,15 +235,15 @@ static public class Updater implements Runnable { protected ApplicationConfig config; - protected URL url; + protected String vfsPropertiesUrl; protected File currentDir; protected File destDir; protected ApplicationUpdaterCallback callback; - public Updater(ApplicationConfig config, URL url, + public Updater(ApplicationConfig config, String vfsPropertiesUrl, File currentDir, File destDir, ApplicationUpdaterCallback callback) { this.config = config; - this.url = url; + this.vfsPropertiesUrl = vfsPropertiesUrl; this.currentDir = currentDir; this.destDir = destDir; this.callback = callback; @@ -255,8 +258,8 @@ */ public void run() { try { - Proxy proxy = getProxy(config); - ApplicationConfig releaseConfig = getUpdaterConfig(proxy); + FileSystemOptions vfsConfig = getVFSConfig(config); + ApplicationConfig releaseConfig = getUpdaterConfig(vfsConfig, vfsPropertiesUrl); List<String> appNames = getApplicationName(releaseConfig); Map<String, String> appVersions = getCurrentVersion(appNames, currentDir); @@ -291,7 +294,7 @@ String app = appInfo.getKey(); ApplicationInfo info = appInfo.getValue(); try { - doUpdate(proxy, appInfo.getValue()); + doUpdate(vfsConfig, appInfo.getValue()); } catch (Exception eee) { appUpdateError.put(app, eee); try { @@ -321,7 +324,7 @@ log.warn("Can't update"); log.info("Application update aborted because: ", eee); if (callback != null) { - callback.aborted(String.valueOf(url), eee); + callback.aborted(vfsPropertiesUrl, eee); } } } @@ -337,20 +340,13 @@ * @param info information sur l'application a mettre a jour * @throws Exception */ - protected void doUpdate(Proxy proxy, ApplicationInfo info) throws Exception { + protected void doUpdate(FileSystemOptions vfsConfig, ApplicationInfo info) throws Exception { if (info.destDir != null) { - // suppression d'une ancienne version si elle existait File dest = new File(info.destDir, info.name); - if (dest.exists()) { - log.warn(String.format("Remove destination directory for new data '%s'", dest)); - FileUtils.deleteDirectory(dest); - } + deepCopy(vfsConfig, info.url, dest.getAbsolutePath()); - URL applicationURL = toURL(info.url); - InputStream in = new BufferedInputStream( - applicationURL.openConnection(proxy).getInputStream()); - ZipUtil.uncompressAndRename(in, info.destDir, "^[^/]+", info.name); - File versionFile = new File(info.destDir, info.name + File.separator + VERSION_FILE); + // ajout du fichier de version + File versionFile = new File(dest, VERSION_FILE); FileUtils.writeStringToFile(versionFile, info.newVersion); log.info(String.format( "Application '%s' is uptodate with version '%s' in '%s'", @@ -361,21 +357,51 @@ } /** - * Converti le path en URL. Path doit etre une URL, mais pour les fichiers + * Recupere le contenu du repertoire de l'archive pour le mettre dans targetPath + * si targetPath existait deja, il est supprime au prealable. + * + * Si l'archive a plus d'un repertoire root, une exception est levee + * + * @param srcPath source path de la forme vfs2 ex:"zip:http://www.nuiton.org/attachments/download/830/nuiton-utils-2.6.5-deps.zip" + * @param targetPath le path destination + * @throws FileSystemException + */ + protected void deepCopy(FileSystemOptions vfsConfig, + String srcPath, String targetPath) throws FileSystemException { + FileSystemManager fsManager = VFS.getManager(); + FileObject archive = fsManager.resolveFile(toVfsURL(srcPath), vfsConfig); + + FileObject[] children = archive.getChildren(); + if (children.length == 1) { + FileObject child = children[0]; + + FileObject target = fsManager.resolveFile(toVfsURL(targetPath), vfsConfig); + target.delete(new AllFileSelector()); + target.copyFrom(child, new AllFileSelector()); + } else { + throw new RuntimeException("must have only one root directory"); + } + } + + /** + * Converti le path en URL vfs2. Path doit etre une URL, mais pour les fichiers * au lieu d'etre absolue ils peuvent etre relatif, un traitement special * est donc fait pour ce cas. Cela est necessaire pour facilement faire * des tests unitaires independant de la machine ou il sont fait - * + * * @param path - * @return + * @return */ - protected URL toURL(String path) throws MalformedURLException { - URL result; - if (StringUtils.startsWith(path, "file:")) { - File f = new File(StringUtils.substringAfter(path, "file:")); - result = f.toURI().toURL(); - } else { - result = new URL(path); + protected String toVfsURL(String path) { + String result = path; + Pattern p = Pattern.compile("(.*?file:)([^/][^!]*)(.*)"); + Matcher m = p.matcher(path); + if (m.matches()) { + String filepath = m.group(2); + File f = new File(filepath); + result = path.replaceAll( + "(.*?file:)([^/][^!]*)(.*)", + "$1"+f.getAbsolutePath()+"$3"); } return result; } @@ -386,27 +412,35 @@ * @return * @throws Exception */ - protected ApplicationConfig getUpdaterConfig(Proxy proxy) throws Exception { + protected ApplicationConfig getUpdaterConfig(FileSystemOptions vfsConfig, String vfsPropertiesUrl) throws Exception { String osName = StringUtils.lowerCase(config.getOsName()); String osArch = StringUtils.lowerCase(config.getOsArch()); // take only first part for osName (windows 2000 or windows 2003 -> windows) osName = StringUtils.substringBefore(osName, " "); if (log.isDebugEnabled()) { - log.debug(String.format( - "Try to load properties from '%s' with proxy '%s'", - url, proxy)); + log.debug(String.format("Try to load properties from '%s'", vfsPropertiesUrl)); } - - InputStream in = new BufferedInputStream( - url.openConnection(proxy).getInputStream()); + Properties prop = new Properties(); - prop.load(in); + FileSystemManager fsManager = VFS.getManager(); + FileObject properties = fsManager.resolveFile(toVfsURL(vfsPropertiesUrl), vfsConfig); + try { + InputStream in = new BufferedInputStream(properties.getContent().getInputStream()); + prop.load(in); + } finally { + try { + properties.close(); + } catch (Exception doNothing) { + log.debug("Can't close vfs file", doNothing); + } + } + if (log.isDebugEnabled()) { log.debug(String.format( "Properties loaded from '%s'\n%s", - url, prop)); + vfsPropertiesUrl, prop)); } // load config with new properties as default @@ -422,12 +456,12 @@ /** * Recupere le proxy http a utiliser pour les connexions reseaux - * + * * @param config * @return */ - protected Proxy getProxy(ApplicationConfig config) { - Proxy result = Proxy.NO_PROXY; + protected FileSystemOptions getVFSConfig(ApplicationConfig config) { + FileSystemOptions result = new FileSystemOptions(); String proxyHost = config.getOption(HTTP_PROXY); try { proxyHost = StringUtils.substringAfter(proxyHost, "://"); @@ -435,9 +469,11 @@ String hostname = StringUtils.substringBefore(proxyHost, ":"); String port = StringUtils.substringAfter(proxyHost, ":"); if (StringUtils.isNumeric(port)) { + int portNumber = Integer.parseInt(port); - SocketAddress socket = new InetSocketAddress(hostname, portNumber); - result = new Proxy(Proxy.Type.HTTP, socket); + + HttpFileSystemConfigBuilder.getInstance().setProxyHost(result, hostname); + HttpFileSystemConfigBuilder.getInstance().setProxyPort(result, portNumber); } else { log.warn(String.format("Invalide proxy port number '%s', not used proxy", port)); } Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationUpdaterTest.java =================================================================== --- trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationUpdaterTest.java 2013-01-04 15:51:26 UTC (rev 2459) +++ trunk/nuiton-utils/src/test/java/org/nuiton/util/ApplicationUpdaterTest.java 2013-01-05 02:50:34 UTC (rev 2460) @@ -47,7 +47,7 @@ @Test public void testUpdate() throws Exception { ApplicationUpdater up = new ApplicationUpdater(); - URL url = new File("src/test/resources/properties/ApplicationUpdaterTest.properties").toURI().toURL(); + String url = "file:src/test/resources/properties/ApplicationUpdaterTest.properties"; File current = new File("src/test/resources/ApplicationUpdater"); File dest = new File("target/test/ApplicationUpdater/NEW"); up.update(url, current, dest, false, new Callback()); @@ -56,7 +56,7 @@ @Test public void testUpdateNetwork() throws Exception { ApplicationUpdater up = new ApplicationUpdater(); - URL url = new URL("http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources..."); + String url = "http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources..."; File current = new File("src/test/resources/ApplicationUpdater"); File dest = new File("target/test/ApplicationUpdater/NEWNETWORK"); up.update(url, current, dest, false, new Callback()); Modified: trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterNetworkTest.properties =================================================================== --- trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterNetworkTest.properties 2013-01-04 15:51:26 UTC (rev 2459) +++ trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterNetworkTest.properties 2013-01-05 02:50:34 UTC (rev 2460) @@ -1,6 +1,6 @@ App1.version=0.3 -App1.url=http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources... +App1.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources... linux.App3.version=8 -linux.App3.url=http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources... +linux.App3.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources... linux.amd64.App2.version=7 -linux.amd64.App2.url=http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources... +linux.amd64.App2.url=zip:http://svn.nuiton.org/svn/nuiton-utils/trunk/nuiton-utils/src/test/resources... Modified: trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterTest.properties =================================================================== --- trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterTest.properties 2013-01-04 15:51:26 UTC (rev 2459) +++ trunk/nuiton-utils/src/test/resources/properties/ApplicationUpdaterTest.properties 2013-01-05 02:50:34 UTC (rev 2460) @@ -1,6 +1,6 @@ App1.version=0.3 -App1.url=file:src/test/resources/ApplicationUpdater/zip/App1-0.3.zip +App1.url=zip:file:src/test/resources/ApplicationUpdater/zip/App1-0.3.zip linux.App3.version=8 -linux.App3.url=file:src/test/resources/ApplicationUpdater/zip/App3-7.zip +linux.App3.url=zip:file:src/test/resources/ApplicationUpdater/zip/App3-7.zip linux.amd64.App2.version=7 -linux.amd64.App2.url=file:src/test/resources/ApplicationUpdater/zip/App2-7.zip +linux.amd64.App2.url=zip:file:src/test/resources/ApplicationUpdater/zip/App2-7.zip Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2013-01-04 15:51:26 UTC (rev 2459) +++ trunk/pom.xml 2013-01-05 02:50:34 UTC (rev 2460) @@ -147,6 +147,24 @@ <dependencies> <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.4.1</version> + </dependency> + + <dependency> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + <version>3.1</version> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-vfs2</artifactId> + <version>2.0</version> + </dependency> + + <dependency> <groupId>org.nuiton.i18n</groupId> <artifactId>nuiton-i18n</artifactId> <version>${nuitonI18nVersion}</version>