org.nuiton.updater.ApplicationUpdaterActionUpdate Maven / Gradle / Ivy
package org.nuiton.updater;
/*
* #%L
* Nuiton Application Updater
* $Id: ApplicationUpdaterActionUpdate.java 2588 2013-07-20 14:25:42Z tchemit $
* $HeadURL: https://nuiton.org/svn/nuiton-updater/tags/nuiton-updater-3.0-alpha-2/src/main/java/org/nuiton/updater/ApplicationUpdaterActionUpdate.java $
* %%
* Copyright (C) 2013 CodeLutin, Tony Chemit
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
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.nuiton.config.ApplicationConfig;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* Apply available updates.
*
* @author tchemit
* @since 2.6.12
*/
public class ApplicationUpdaterActionUpdate extends AbstractApplicationUpdaterAction {
/** Logger. */
private static final Log log =
LogFactory.getLog(ApplicationUpdaterActionUpdate.class);
protected ApplicationUpdaterCallback callback;
protected DownloadMonitor downloadMonitor;
protected File destDir;
public ApplicationUpdaterActionUpdate(ApplicationConfig config,
String vfsPropertiesUrl,
File currentDir,
File destDir,
DownloadMonitor downloadMonitor,
ApplicationUpdaterCallback callback) {
super(config, vfsPropertiesUrl, currentDir);
this.destDir = destDir;
this.downloadMonitor = downloadMonitor;
this.callback = callback;
}
/**
* Recupere le fichier properties contenant les informations de mise a jour
* liste les applications et leur version actuelle
* pour chaque application a mettre a jour recupere le zip et le decompresse
*
* Si callback existe envoi les messages necessaires
*/
@Override
public void run() {
try {
FileSystemOptions vfsConfig = getVFSConfig(config);
ApplicationConfig releaseConfig = getUpdaterConfig(
vfsConfig, vfsPropertiesUrl);
Map appToUpdate = getVersions(
releaseConfig, false, destDir);
// offre la possibilite a l'appelant de modifier les valeurs par defaut
if (callback != null) {
appToUpdate = callback.updateToDo(appToUpdate);
}
// mise a jour
Map appUpdateError = new HashMap();
for (Map.Entry appInfo : appToUpdate.entrySet()) {
String app = appInfo.getKey();
ApplicationInfo info = appInfo.getValue();
try {
doUpdate(vfsConfig, appInfo.getValue());
} catch (Exception eee) {
onUpdateError(app, info, appUpdateError, eee);
}
}
// envoi le resultat a l'appelant s'il le souhaite
if (callback != null) {
callback.updateDone(appToUpdate, appUpdateError);
}
} catch (Exception eee) {
log.warn("Can't update");
log.info("Application update aborted because: ", eee);
if (callback != null) {
callback.aborted(vfsPropertiesUrl, eee);
}
}
}
protected void onUpdateError(String app,
ApplicationInfo info,
Map appUpdateError,
Exception eee) {
appUpdateError.put(app, eee);
log.warn(String.format(
"Can't update application '%s' with url '%s'",
app, info.url));
log.debug("Application update aborted because: ", eee);
try {
// clear data if error occur during uncompress operation
File dest = new File(info.destDir, info.name);
if (dest.exists()) {
log.debug(String.format("Cleaning destination directory due to error '%s'", dest));
FileUtils.deleteDirectory(dest);
}
} catch (Exception doNothing) {
log.debug("Can't clean directory", doNothing);
}
}
/**
* Decompresse le zip qui est pointer par l'url dans le repertoire
* specifie, et ajoute le fichier contenant la version de l'application.
* Le repertoire root du zip est renomme par le nom de l'application.
* Par exemple si un fichier se nomme "monApp-1.2/Readme.txt" il se
* nommera au final "monApp/Readme.txt"
*
* @param vfsConfig le proxy a utiliser pour la connexion a l'url
* @param info information sur l'application a mettre a jour
* @throws Exception
*/
protected void doUpdate(FileSystemOptions vfsConfig,
ApplicationInfo info) throws Exception {
if (info.destDir != null) {
File dest = new File(info.destDir, info.name);
String url = toVfsURL(info.url);
if (info.needAuthentication) {
url = StringUtils.replaceOnce(url, "://",
String.format("://%s:%s@", info.login, new String(info.password)));
}
if (callback != null) {
callback.startUpdate(info);
}
// le type de l'archive contenant la mise à jour
String archiveType = url.substring(0, url.indexOf(':'));
// recuperation de l'archive en locale (dans /tmp)
File archive = downloadUpdate(vfsConfig, info, url.substring(archiveType.length() + 1));
// extraction depuis l'archive téléchargée de l'unique répertoire vers la destination
explodeUpdate(vfsConfig,
info,
archiveType,
archive,
dest);
// ajout du fichier de version
ApplicationUpdater.createVersionFile(dest, info.newVersion);
log.info(String.format(
"Application '%s' is uptodate with version '%s' in '%s'",
info.name, info.newVersion, info.destDir));
} else {
log.info(String.format("Update for '%s' aborted because destination dir is set to null", info.name));
}
}
/**
* Télécharge une archive dans un fichier temporaraire.
*
* Si l'archive a plus d'un repertoire root, une exception est levee
*
* @param vfsConfig configuration of vsf (
* @param info
* @param srcPath source path de la forme vfs2 ex:"zip:http://www.nuiton.org/attachments/download/830/nuiton-utils-2.6.5-deps.zip"
* @throws FileSystemException
*/
protected File downloadUpdate(FileSystemOptions vfsConfig,
ApplicationInfo info,
String srcPath) throws IOException {
FileSystemManager fsManager = VFS.getManager();
FileObject source = fsManager.resolveFile(srcPath, vfsConfig);
if (!source.exists()) {
throw new UpdateNotFoundException(info);
}
File result = new File(FileUtils.getTempDirectory(),
source.getName().getBaseName() +
'_' + System.nanoTime());
FileObject target = fsManager.toFileObject(result);
InputStream input = source.getContent().getInputStream();
try {
OutputStream output = target.getContent().getOutputStream();
try {
long inputSize = source.getContent().getSize();
if (downloadMonitor != null) {
downloadMonitor.setSize(inputSize);
}
long count = 0;
int n;
byte[] buffer = new byte[1024];
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
if (downloadMonitor != null) {
downloadMonitor.setCurrent(count);
}
}
output.close();
} finally {
IOUtils.closeQuietly(output);
}
input.close();
} finally {
IOUtils.closeQuietly(input);
}
return result;
}
/**
* Recopie le contenu du répertoire de l'archive dans le
* répertoire {@code target}.
*
* Si le répertoire cible existe déjà, il sera alors vidé.
*
* Si l'archive ne contient pas exactement un répertoire alors une exception est levée
*
* @param archiveType le type de l'archive
* @param source l'archive à décompresser
* @param target le répertoire cible
* @throws FileSystemException
* @throws UpdateInvalidArchiveLayoutException
* si l'archive n'a pas le bon format
*/
protected void explodeUpdate(FileSystemOptions vfsConfig,
ApplicationInfo info,
String archiveType,
File source,
File target) throws FileSystemException, UpdateInvalidArchiveLayoutException {
FileSystemManager fsManager = VFS.getManager();
FileObject sourceObject = fsManager.resolveFile(archiveType + ":" + source.getAbsolutePath(), vfsConfig);
FileObject[] children = sourceObject.getChildren();
if (children.length != 1) {
throw new UpdateInvalidArchiveLayoutException(info, source);
}
// clean target
FileObject targetObject = fsManager.toFileObject(target);
targetObject.delete(new AllFileSelector());
//copy to it the archive only directory
FileObject child = children[0];
targetObject.copyFrom(child, new AllFileSelector());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy