OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 14 → Rev 15

/trunk/OpenConcerto/src/org/openconcerto/ftp/FTPUtils.java
New file
0,0 → 1,91
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ftp;
 
import org.openconcerto.utils.RecursionType;
import org.openconcerto.utils.cc.ExnClosure;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
 
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
 
public final class FTPUtils {
 
private FTPUtils() {
}
 
// MAYBE use recurse, but can't recursively pass local
static public final void saveR(FTPClient ftp, File local) throws IOException {
local.mkdirs();
for (FTPFile child : ftp.listFiles()) {
final String childName = child.getName();
if (childName.indexOf('.') != 0) {
if (child.isDirectory()) {
ftp.changeWorkingDirectory(childName);
saveR(ftp, new File(local, childName));
ftp.changeToParentDirectory();
} else {
final OutputStream outs = new FileOutputStream(new File(local, childName));
ftp.retrieveFile(childName, outs);
outs.close();
}
}
}
}
 
static public final void rmR(final FTPClient ftp, final String toRm) throws IOException {
final String cwd = ftp.printWorkingDirectory();
// si on ne peut cd, le dossier n'existe pas
if (ftp.changeWorkingDirectory(toRm)) {
recurse(ftp, new ExnClosure<FTPFile, IOException>() {
@Override
public void executeChecked(FTPFile input) throws IOException {
final boolean res;
if (input.isDirectory())
res = ftp.removeDirectory(input.getName());
else
res = ftp.deleteFile(input.getName());
if (!res)
throw new IOException("unable to delete " + input);
}
}, RecursionType.DEPTH_FIRST);
}
ftp.changeWorkingDirectory(cwd);
ftp.removeDirectory(toRm);
}
 
static public final void recurse(FTPClient ftp, ExnClosure<FTPFile, ?> c) throws IOException {
recurse(ftp, c, RecursionType.DEPTH_FIRST);
}
 
static public final void recurse(FTPClient ftp, ExnClosure<FTPFile, ?> c, RecursionType type) throws IOException {
for (FTPFile child : ftp.listFiles()) {
if (child.getName().indexOf('.') != 0) {
if (type == RecursionType.BREADTH_FIRST)
c.executeCheckedWithExn(child, IOException.class);
if (child.isDirectory()) {
ftp.changeWorkingDirectory(child.getName());
recurse(ftp, c, type);
ftp.changeToParentDirectory();
}
if (type == RecursionType.DEPTH_FIRST)
c.executeCheckedWithExn(child, IOException.class);
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/ftp/CopyFileListener.java
New file
0,0 → 1,22
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ftp;
 
import java.io.File;
 
public interface CopyFileListener {
 
public void bytesTransferred(File source, long totalBytesTransferred, int bytesTransferred, long streamSize);
 
}
/trunk/OpenConcerto/src/org/openconcerto/ftp/IFtp.java
New file
0,0 → 1,229
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ftp;
 
import org.openconcerto.utils.CollectionMap;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.MessageDigestUtils;
import org.openconcerto.utils.RecursionType;
import org.openconcerto.utils.StringInputStream;
import org.openconcerto.utils.cc.ExnClosure;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPCommand;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.io.CopyStreamAdapter;
import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;
import org.apache.commons.net.io.Util;
 
public class IFtp extends FTPClient {
 
// *** Static
 
private static final String MD5_SUFFIX = ".md5";
private static final int MD5_LENGTH = 32;
 
private static final String md5ToName(String fname, String md5) {
if (md5.length() != MD5_LENGTH)
throw new IllegalArgumentException("md5 size must be " + MD5_LENGTH + " : " + md5);
return fname + "_" + md5 + MD5_SUFFIX;
}
 
// *** Instance
 
private final ThreadLocal<CopyStreamListener> streamListeners = new ThreadLocal<CopyStreamListener>();
 
@Override
public boolean login(String username, String password) throws IOException {
final boolean res = super.login(username, password);
this.setFileType(FTP.BINARY_FILE_TYPE);
return res;
}
 
public List<File> sync(File lDir) throws IOException, NoSuchAlgorithmException {
return this.sync(lDir, null);
}
 
public List<File> sync(File lDir, CopyFileListener l) throws IOException, NoSuchAlgorithmException {
return this.sync(lDir, l, false);
}
 
// path separator (/) is not standard, so cd first where you want to upload
public List<File> sync(File ldir, final CopyFileListener l, boolean forceUpload) throws IOException, NoSuchAlgorithmException {
// there might be more than one md5 per file, if an error occured during the last sync()
final CollectionMap<String, String> nameToMD5s = new CollectionMap<String, String>();
final Map<String, FTPFile> ftpFiles = new HashMap<String, FTPFile>();
final FTPFile[] listFiles = this.listFiles();
if (listFiles == null) {
System.out.println("IFtp.sync(): listFiles null :" + ldir.getName());
return new ArrayList<File>();
}
 
for (int i = 0; i < listFiles.length; i++) {
FTPFile rFile = listFiles[i];
// Oui ca arrive!
if (rFile != null) {
// some FTP servers returns 450 when NLST an empty directory, so use LIST
final String name = rFile.getName();
if (name != null) {
if (name.endsWith(MD5_SUFFIX)) {
// originalName_a045d5e6.md5
final int underscore = name.length() - MD5_SUFFIX.length() - MD5_LENGTH - 1;
if (underscore >= 0) {
final String fname = name.substring(0, underscore);
final String md5 = name.substring(underscore + 1, underscore + 1 + MD5_LENGTH);
nameToMD5s.put(fname, md5);
}
} else {
ftpFiles.put(name, rFile);
}
} else {
System.out.println("IFtp.sync(): rFile.getName() null : [" + i + "]" + ldir.getName());
}
} else {
System.out.println("IFtp.sync(): rFile null : [" + i + "]" + ldir.getName());
}
 
}
 
final List<File> uploaded = new ArrayList<File>();
final List<File> dirs = new ArrayList<File>();
for (final File lFile : ldir.listFiles()) {
if (lFile.isFile() && lFile.canRead()) {
final String lName = lFile.getName();
final List<String> md5List = (List<String>) nameToMD5s.getNonNull(lName);
final String lMD5 = MessageDigestUtils.getMD5(lFile);
boolean shouldUpload = true;
if (!forceUpload && ftpFiles.containsKey(lFile.getName())) {
final long lSize = lFile.length();
final long rSize = ftpFiles.get(lFile.getName()).getSize();
shouldUpload = lSize != rSize || !lMD5.equalsIgnoreCase(CollectionUtils.getSole(md5List));
}
if (shouldUpload) {
// delete all previous
for (final String md5 : md5List) {
this.deleteFile(md5ToName(lName, md5));
}
if (l != null) {
final long fileSize = lFile.length();
this.streamListeners.set(new CopyStreamAdapter() {
@Override
public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize) {
l.bytesTransferred(lFile, totalBytesTransferred, bytesTransferred, fileSize);
}
});
}
this.storeFile(lName, new FileInputStream(lFile));
// don't signal the MD5 file to the listener
this.streamListeners.set(null);
this.storeFile(md5ToName(lName, lMD5), new StringInputStream(lMD5 + "\t" + lName));
uploaded.add(lFile);
}
} else if (lFile.isDirectory())
dirs.add(lFile);
// ignore other types of file
}
for (final File dir : dirs) {
this.makeDirectory(dir.getName());
if (!this.changeWorkingDirectory(dir.getName()))
throw new IllegalStateException("could not cd to " + dir.getName());
uploaded.addAll(this.sync(dir, l, forceUpload));
this.changeToParentDirectory();
}
return uploaded;
}
 
public final void saveR(File local) throws IOException {
FTPUtils.saveR(this, local);
}
 
public void rmR(String toRm) throws IOException {
FTPUtils.rmR(this, toRm);
}
 
public final void recurse(ExnClosure<FTPFile, ?> c) throws IOException {
recurse(c, RecursionType.DEPTH_FIRST);
}
 
public final void recurse(ExnClosure<FTPFile, ?> c, RecursionType type) throws IOException {
FTPUtils.recurse(this, c, type);
}
 
// our __storeFile use CopyStreamListener
private boolean __storeFile(int command, String remote, InputStream local) throws IOException {
OutputStream output;
Socket socket;
 
if ((socket = _openDataConnection_(command, remote)) == null)
return false;
 
output = new BufferedOutputStream(socket.getOutputStream(), getBufferSize());
 
// __fileType is private, if we really want we could subclass setFileType() to have access
// if (__fileType == ASCII_FILE_TYPE)
// output = new ToNetASCIIOutputStream(output);
 
// Treat everything else as binary for now
try {
final CopyStreamListener l = this.streamListeners.get();
final long size = CopyStreamEvent.UNKNOWN_STREAM_SIZE;
if (l != null) {
// copyStream() doesn't pass 0
l.bytesTransferred(0, 0, size);
}
Util.copyStream(local, output, getBufferSize(), size, l, false);
} catch (IOException e) {
try {
socket.close();
} catch (IOException f) {
}
throw e;
}
output.close();
socket.close();
return completePendingCommand();
}
 
public boolean storeFile(String remote, InputStream local) throws IOException {
return __storeFile(FTPCommand.STOR, remote, local);
}
 
public boolean appendFile(String remote, InputStream local) throws IOException {
return __storeFile(FTPCommand.APPE, remote, local);
}
 
public boolean storeUniqueFile(String remote, InputStream local) throws IOException {
return __storeFile(FTPCommand.STOU, remote, local);
}
 
public boolean storeUniqueFile(InputStream local) throws IOException {
return __storeFile(FTPCommand.STOU, null, local);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ftp/updater/UpdateManager.java
New file
0,0 → 1,259
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ftp.updater;
 
import org.openconcerto.ftp.FTPUtils;
import org.openconcerto.ftp.IFtp;
import org.openconcerto.utils.FileUtils;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Properties;
 
import javax.swing.JOptionPane;
 
public class UpdateManager implements Runnable {
private Thread thread;
private String login;
private String pass;
private String server;
private String file;
private static boolean stop = false;
 
private static final int UPDATE_COUNT = 2;
private static int counter = UPDATE_COUNT;
private boolean enabled;
 
UpdateManager() {
 
final Properties props = new Properties();
final File f = new File("Configuration/update.properties");
if (f.exists()) {
try {
props.load(new FileInputStream("Configuration/update.properties"));
this.login = props.getProperty("login");
this.pass = props.getProperty("pass");
this.server = props.getProperty("ftpserver");
this.file = props.getProperty("file");
this.enabled = Boolean.parseBoolean(props.getProperty("enabled"));
if (!this.enabled) {
System.out.println("Mise à jour désactivées");
} else {
this.thread = new Thread(this);
this.thread.setDaemon(true);
this.thread.setPriority(Thread.MIN_PRIORITY);
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println("Mise à jour désactivées (fichier de configuration manquant)");
}
 
}
 
public static synchronized void start() {
 
UpdateManager u = new UpdateManager();
if (!u.isStarted()) {
u.startWatcher();
} else {
throw new RuntimeException("UpdateManager already started");
}
}
 
public static synchronized void stop() {
stop = true;
}
 
public static synchronized void forceUpdate() {
counter = UPDATE_COUNT;
 
}
 
private boolean isStarted() {
if (thread == null) {
return false;
}
return this.thread.isAlive();
}
 
private void startWatcher() {
if (this.enabled) {
this.thread.start();
}
}
 
@Override
public void run() {
System.err.println("UpdateManager started");
 
while (!stop) {
if (counter >= UPDATE_COUNT) {
counter = 0;
// Update
final IFtp ftp = new IFtp();
BufferedReader bReaderRemote = null;
try {
ftp.connect(this.server);
 
boolean logged = ftp.login(this.login, this.pass);
 
if (!logged) {
throw new IllegalStateException("Identifiants refusés");
}
bReaderRemote = new BufferedReader(new InputStreamReader(ftp.retrieveFileStream(this.file)));
 
int newVersion = Integer.parseInt(bReaderRemote.readLine());
 
BufferedReader bReaderLocal = null;
int currentVersion = -1;
try {
bReaderLocal = new BufferedReader(new FileReader(".version"));
currentVersion = Integer.parseInt(bReaderLocal.readLine());
} catch (Exception e) {
// TODO Auto-generated catch block
System.err.println(".version manquant");
 
} finally {
if (bReaderLocal != null) {
bReaderLocal.close();
}
}
 
// / marche pas: ftp.quit();
 
if (newVersion > currentVersion) {
Object[] options = { "Maintenant", "Plus tard" };
int res = JOptionPane.showOptionDialog(null, "Une mise à jour est disponible. Installer la mise à jour:", "Mises à jour automatiques", JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE, null, options, options[0]);
if (res == 0) {
update(newVersion);
}
 
}
 
} catch (Exception e) {
Object[] options = { "Réessayer dans 1 minute", "Abandonner" };
int res = JOptionPane.showOptionDialog(null, "Impossible de se connecter au serveur de mises à jour.\n" + e.getMessage(), "Mises à jour automatiques", JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE, null, options, options[0]);
if (res == 0) {
counter--;
} else {
stop = true;
}
e.printStackTrace();
 
} finally {
try {
System.err.println("Disconnect start");
if (bReaderRemote != null) {
bReaderRemote.close();
}
// ftp.abort();
// ftp.logout();
// ftp.disconnect();
ftp.quit();
System.err.println("Disconnected start");
} catch (Exception e) {
e.printStackTrace();
}
}
 
}
if (!stop) {
try {
// Sleep 1 minute
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
counter++;
}
System.err.println("UpdateManager stopped");
}
 
private void update(int toVersion) {
System.out.println("Update application");
File tempDir = new File("Update");
if (tempDir.exists()) {
FileUtils.rmR(tempDir);
 
}
tempDir.mkdir();
File f = new File("Update/.version");
FileOutputStream fOp;
try {
fOp = new FileOutputStream(f);
 
PrintStream out = new PrintStream(fOp);
out.println(toVersion);
out.close();
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(null, "Impossible de créer le .version");
}
final IFtp ftp = new IFtp();
try {
ftp.connect(this.server);
boolean logged = ftp.login(this.login, this.pass);
if (!logged) {
JOptionPane.showMessageDialog(null, "Impossible d'accéder au serveur FTP pour récupérer les fichiers");
ftp.disconnect();
return;
}
String dir = this.file;
int i = dir.lastIndexOf('.');
if (i > 0) {
dir = dir.substring(0, i);
}
 
boolean cwdOk = ftp.changeWorkingDirectory(dir);
if (!cwdOk) {
JOptionPane.showMessageDialog(null, "Impossible d'accéder au dossier " + dir + " du serveur FTP");
ftp.disconnect();
return;
}
FTPUtils.saveR(ftp, tempDir);
 
if (tempDir.getAbsolutePath().contains("workspace") && !tempDir.getAbsolutePath().contains("dist")) {
JOptionPane.showMessageDialog(null, "Mise à jour desactivée en version non 'dist'");
ftp.disconnect();
return;
}
final String updaterFilename = "Update/update.exe";
if (!new File(updaterFilename).exists()) {
JOptionPane.showMessageDialog(null, "Le fichier 'Update/update.exe' est manquant.");
ftp.disconnect();
return;
}
Runtime.getRuntime().exec(updaterFilename);
ftp.disconnect();
System.exit(0);
 
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Impossible de récupérer les fichiers");
 
}
 
}
}