FTP Webapplication mit Dokumentenverwaltung

D

DerMajo

Gast
Hallo :)

Ich arbeite mit Oracle ADF BC 10 und entwickel eine Webapplikation, die unter anderen eine Dokumentenverwaltung beinhaltet. Bei meinem Problem handelt es sich lediglich um den Part des von mir implementierten FTP-Clients bzw. um die gesamte Dokumentenverwaltung.

Die Dokumentenverwaltung funktioniert soweit, dass ich eine Datei auf dem App-Server hochladen kann und von dort auf den FTP. Ebenso funktioniert der Download. Allerdings tritt hier manchmal ein Problem auf.
Und zwar habe ich eine Tabelle auf der Weboberfläche, in der Dokumente als Link aufgelistet sind. Normalerweise läd man das Dokument runter in dem man auf den Link klickt. Nun passiert es ab und zu, dass ein vorheriges Dokument runtergeladen wird, obwohl ich auf ein anderes geklickt habe. Ich weiß auch schon, warum das passiert. Und zwar handhabe ich die Dateien über byte-Arrays. So wird mir ein Fehler vom FTP gemeldet, den ich nicht behandel und das alte byte-Array heruntergeladen, da es nicht vom FTP-Client überschrieben/erneuert wurde.

Ein sauberer Download sieht in meiner Konsole wie folgt aus:
Java:
10/08/13 10:27:51 Document: Dokument1.pdf
CWD /
250 CWD command successful
TYPE I
200 Type set to I
PORT [...]
200 PORT command successful
RETR /Dokument1.pdf
150 Opening BINARY mode data connection for Dokument1.pdf (90028 bytes)
226 Transfer complete
QUIT
221 Goodbye.

Wenn der Fehler auftritt sieht der Log so aus:
Java:
10/08/13 10:27:51 Document: Dokument2.pdf
CWD /
250 CWD command successful
TYPE I
200 Type set to I
PORT [...]
200 PORT command successful
RETR /Dokument2.pdf
150 Opening BINARY mode data connection for Dokument2.pdf (90028 bytes)
426 Transfer aborted. Operation not permitted
QUIT
221 Goodbye.

Das kurriose daran ist, dass es nicht immer auftritt. Auch nicht unbedingt bei kleinen oder großen Dateien. Mit jedem Download mache ich eine Verbindung auf und danach wieder zu. Es existiert quasi keine globale ständige Verbindung zu dem FTP (was auch seine Gründe hat). Ich glaub eher, dass es irgend ein Timeout vom "Reconnect" zum FTP sein könnte. Kann man da irgendwas prüfen oder am Server einstellen? Die FTP-Server-Einstellungen kann ich leider nicht einsehen, da ich die Admin-Daten nicht kenne.

Hier ein Auszug aus der FTP-Client-aufrufenden Methode:
Java:
                ...
                FtpClient client = null;

                try {
                    client = 
                            new FtpClient("[IP-ADRESSE]", 21, "[FTP_USER]", "[FTP_PASSWORD]");
                } catch (SocketException e) {
                    if (client != null) {
                        try {
                            client.disconnect();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                    e.printStackTrace();
                } catch (IOException e) {
                    if (client != null) {
                        try {
                            client.disconnect();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                    e.printStackTrace();
                }

                byte[] fileData = null;
                try {
                    fileData = 
                            client.downLoadFileFromServer(curRow.getPath(), curRow.getFilename());
                } catch (java.lang.Exception e) {
                    e.printStackTrace();
                } finally {
                    if (client != null) {
                        try {
                            client.disconnect();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
                ...

Was ihr evtl. noch benötigt ist der relevante FTP-Client-Code:
Java:
package demo.model.support.ftp;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;

import java.net.SocketException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;

import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

public class FtpClient {

    public static final String UPLOAD_RETURN_SUCCESS = "upload_success";
    public static final String UPLOAD_CHANGED_FILENAME = 
        "upload_changed_filename";
    public static final String UPLOAD_ORIGNINAL_FILENAME = 
        "upload_origninal_filename";
    public static final String FILE_INFO_NAME = "file_info_name";
    public static final String FILE_INFO_DATE = "file_info_date";
    public static final String FILE_INFO_PATH = "file_info_path";
    public static final String FILE_INFO_CATEGORY = "file_info_category";

    public static final String SEPARATOR = "/"; // File.separator;
    private static final String ROOT_FOLDER = SEPARATOR;

    private String hostName;
    private int port;
    private String userName;
    private String password;

    private static FTPClient client;

    /**
     * Default constructor
     */
    public FtpClient() {
        client = null;
    }

    /**
     * Consturctor
     * @param hostName
     * @param port
     * @param userName
     * @param password
     * @throws SocketException
     * @throws IOException
     */
    public FtpClient(String hostName, int port, String userName, 
                     String password) throws SocketException, IOException {
        this.hostName = hostName;
        this.port = port;
        this.userName = userName;
        this.password = password;

        client = login(hostName, port, userName, password);
    }

    /**
     * logs in as user with password to host:port
     * @param host
     * @param port
     * @param user
     * @param password
     * @return null, if its not possible, else a FTPClient object
     * @throws SocketException
     * @throws IOException
     */
    public FTPClient login(String host, int port, String user, 
                           String password) throws SocketException, 
                                                   IOException {
        FTPClient client = new FTPClient();

        client.connect(host, port);
        if (!client.login(user, password)) {
            System.out.println("Login failed");
            client.logout();
        }

        if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
            client.disconnect();
            return null;
        }

        client.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));

        return client;
    }

    ...

    /**
     * Download the file with fileName in the directory dir as a byte[]
     * @param dir
     * @param fileName
     * @return filedata as a byte[]
     * @throws IOException
     */
    public byte[] downLoadFileFromServer(String dir, 
                                         String fileName) throws IOException {
        InputStream in = null;
        ByteArrayOutputStream bos = null;
        byte[] ba = null;

        try {
            boolean isDirectory = 
                createDirectoryIfNotExsist(ROOT_FOLDER + dir);

            if (isDirectory) {
                client.setFileType(client.BINARY_FILE_TYPE);
                in = client.retrieveFileStream(ROOT_FOLDER + dir + fileName);

                bos = new ByteArrayOutputStream();
                while (in.available() != 0) {
                    bos.write(in.read());
                }

                ba = bos.toByteArray();
            }
        } finally {
            if (in != null)
                in.close();
            if (bos != null)
                bos.close();
            client.completePendingCommand();
        }

        return ba;
    }

    ...

    /**
     * Disconnects the current client
     * @throws IOException
     */
    public void disconnect() throws IOException {
        this.client.logout();
        this.client.disconnect();
    }

    ...

    private boolean createDirectoryIfNotExsist(String path) throws IOException {

        boolean canChangeDir = client.changeWorkingDirectory(SEPARATOR);

        if (canChangeDir) {
            StringTokenizer tokenizer = new StringTokenizer(path, SEPARATOR);
            while (tokenizer.hasMoreTokens()) {
                String folder = tokenizer.nextToken();
                System.out.println("Trying to change to " + folder + 
                                   " folder!");

                canChangeDir = client.changeWorkingDirectory(folder);
                if (!canChangeDir) {
                    System.out.println("Cannot change to folder. Must create it!");
                    client.makeDirectory(folder);
                    canChangeDir = client.changeWorkingDirectory(folder);
                }
                if (!canChangeDir) {
                    System.out.println("Cannot create folder!");
                    return false;
                }
            }
        }
        return true;
    }
}

Ich hoffe ich konnte mein Problem schildern. Wenn nicht, bitte hackt nach, denn ich weiß bei diesem Fehler absolut nicht, woran es liegen könnte.

Liebe Grüße
Majo
 
M

maki

Gast
Du machst wirklich kein richtiges Exceptionhandling, und nein, einfach nur auf die Konsoleausgeben ist kein Exceptionhandling.

imho liegt hier der Hase im Pfeffer:
Java:
                try {
                    client = 
                            new FtpClient("[IP-ADRESSE]", 21, "[FTP_USER]", "[FTP_PASSWORD]");
                } catch (SocketException e) {
                    if (client != null) {
                        try {
                            client.disconnect();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                    e.printStackTrace();
                } catch (IOException e) {
                    if (client != null) {
                        try {
                            client.disconnect();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                    e.printStackTrace();
                }
Sobald du eine Exception bekommst, hast du verloren im Sinne von "Game Over", kannst dem User vielleicht noch eine Meldung ausgeben, das war es dann auch schon.
Stattdessen machst du einfach weiter als ob nix war..
 
D

DerMajo

Gast
Hallo und danke für die schnelle Antwort :)

Das Exceptionhandling ist einfach nur Notgedrungen an die Entwicklungsphase angepasst. Bevor das Tool online geht, werden dort auf jeden Fall noch Meldungen ausgegeben. Zumal ich mit dem Programm weiter machen muss, da es eine Webanwendung ist, die der User nicht mal eben neu initialisieren kann.

Es gibt an der Stelle auch keine Exception, da keine Ausgabe über die Konsole (ex.printStackTrace()) kommt. Also liegt hier definitiv nicht der Hase im Pfeffer. Es sieht nicht schön aus, ist aber auch Kern der Sache.

Fällt dir evtl. drüber hinaus noch etwas auf? Es ist immerhin mein erster FTP-Client, den ich mit apache.commons.net entwickelt habe.


Viele Grüße
Majo
 

Neue Themen


Oben