Package abstrasy.libraries.io

Source Code of abstrasy.libraries.io.External_File$ExtURL

package abstrasy.libraries.io;

/**
* Abstrasy Interpreter
*
* Copyright : Copyright (c) 2006-2012, Luc Bruninx.
*
* Concédée sous licence EUPL, version 1.1 uniquement (la «Licence»).
*
* Vous ne pouvez utiliser la présente oeuvre que conformément à la Licence.
* Vous pouvez obtenir une copie de la Licence à l’adresse suivante:
*
*   http://www.osor.eu/eupl
*
* Sauf obligation légale ou contractuelle écrite, le logiciel distribué sous
* la Licence est distribué "en l’état", SANS GARANTIES OU CONDITIONS QUELLES
* QU’ELLES SOIENT, expresses ou implicites.
*
* Consultez la Licence pour les autorisations et les restrictions
* linguistiques spécifiques relevant de la Licence.
*
*
* @author Luc Bruninx
* @version 1.0
*/


import abstrasy.Bivalence;
import abstrasy.Buffer;
import abstrasy.Hash;
import abstrasy.Interpreter;
import abstrasy.Node;
import abstrasy.SELF;
import abstrasy.Tools;

import abstrasy.externals.AExtCachable;
import abstrasy.externals.AExtClonable;
import abstrasy.externals.AExtTools;
import abstrasy.externals.AExtVObject;
import abstrasy.externals.OptAccess;
import abstrasy.externals.OptAccessList;
import abstrasy.externals.OptAccessProvider;

import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.ORef;
import abstrasy.interpreter.StdErrors;

import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.lang.ref.WeakReference;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;

import java.util.ArrayList;

import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;


public class External_File extends OptAccessProvider implements AExtClonable,
        AExtCachable,
        AExtVObject {

    // l'adaptateur est-il libre?
    private boolean opened = false;

    // encodage des caractères
    private String charset = System.getProperty("file.encoding");

    // séquence de fin de ligne
    private String eolStr = "\n";
    private byte[] eol_bytes = eolStr.getBytes();
    // liste des caractères EOL à filtrer
    private String eolFilterStr = "\r\n";

    private int connectTimeOut = 0;
    private int readTimeOut = 0;

    private File file = null;

    private URLConnection urlConnection = null;

    private String protocol = null;

    private String tcpIP = null;
    private String tcpHost = null;
    private int tcpPort = 0;
    private Socket socket = null;

    private FileInputStream fileInputStream = null;
    private InputStream input = null;


    private FileOutputStream fileOutputStream = null;
    private OutputStream output = null;

    private boolean autoflush = true;


    /*
     * ---------------------------------------------------------------------------------
     *
     *    Gestion des options
     *    ===================
     *
     *
     *    'connect-timeout: ]0-NUMBER]
     *          Indique le nombre de millisecondes avant le time-out à la connexion
     *          d'une url. Si est = à 0, indique qu'il n'y a pas de time-out. Dans ce cas,
     *          l'attente est infinie.
     */

    private OptAccess oa_connect_timeout = new OptAccess("connect-timeout") {

        public Node getNode() {
            return new Node(connectTimeOut);
        }

        public void setNode(Node optNode) throws Exception {
            optNode.requireNodeType(Node.TYPE_NUMBER);
            connectTimeOut = Math.min(0, (int) optNode.getNumber());
        }

    };

    /*
     *    'read-timeout: ]0-NUMBER]
     *          Indique le nombre de milliseconde avant que le time-out de lecture
     *          d'une url soit atteint. Si l'option est à 0, il n'y a pas de limite de
     *          la durée d'attente (il s'agit d'une attente à l'infini).
     */

    private OptAccess oa_read_timeout = new OptAccess("read-timeout") {

        public Node getNode() {
            return new Node(readTimeOut);
        }

        public void setNode(Node optNode) throws Exception {
            optNode.requireNodeType(Node.TYPE_NUMBER);
            readTimeOut = Math.min(0, (int) optNode.getNumber());
        }

    };

    /*
     *    'charset:
     *          Quel est l'encodage des caractères. Par défaut, il s'agit de
     *          l'encodage du système d'exploitation.
     */

    private OptAccess oa_charset = new OptAccess("charset") {

        public Node getNode() {
            return charset == null ? Node.createNothing(): new Node(charset);
        }

        public void setNode(Node optNode) throws Exception {
            optNode.requireNodeType(Node.TYPE_STRING);
            setCharset(optNode.getString());
        }

    };

    private OptAccess oa_autoflush = new OptAccess("autoflush") {

        public Node getNode() {
            return new Node(isAutoflush() ? Node.TRUE: Node.FALSE);
        }

        public void setNode(Node optNode) throws Exception {
            optNode.requireNodeType(Node.VTYPE_TRUEEQUIVALENT);
            setAutoflush(Node.isTrueEquivalent(optNode));
        }

    };

    private OptAccess oa_eol_sequence = new OptAccess("eol-sequence") {

        public Node getNode() {
            return new Node(eolStr);
        }

        public void setNode(Node optNode) throws Exception {
            optNode.requireNodeType(Node.TYPE_STRING);
            setEolStr(optNode.getString());
        }

    };

    private OptAccess oa_eol_filter = new OptAccess("eol-filter") {

        public Node getNode() {
            return new Node(eolFilterStr);
        }

        public void setNode(Node optNode) throws Exception {
            optNode.requireNodeType(Node.TYPE_STRING);
            setEolFilterStr(optNode.getString());
        }

    };

    private OptAccess oa_Protocol = new OptAccess("Protocol") {

        public Node getNode() {
            return protocol == null ? Node.NOTHING_FINAL_NODE: new Node(protocol);
        }

        public void setNode(Node optNode) throws Exception {
            throw new InterpreterException(StdErrors.Illegal_access_to_final_value);
        }

    };

    private OptAccess oa_Host = new OptAccess("Host") {

        public Node getNode() {
            return tcpHost == null ? Node.NOTHING_FINAL_NODE: new Node(tcpHost);
        }

        public void setNode(Node optNode) throws Exception {
            throw new InterpreterException(StdErrors.Illegal_access_to_final_value);
        }

    };

    private OptAccess oa_IP = new OptAccess("IP") {

        public Node getNode() {
            return tcpIP == null ? Node.NOTHING_FINAL_NODE: new Node(tcpIP);
        }

        public void setNode(Node optNode) throws Exception {
            throw new InterpreterException(StdErrors.Illegal_access_to_final_value);
        }

    };

    private OptAccess oa_Port = new OptAccess("Port") {

        public Node getNode() {
            return new Node(tcpPort);
        }

        public void setNode(Node optNode) throws Exception {
            throw new InterpreterException(StdErrors.Illegal_access_to_final_value);
        }

    };

    private OptAccess[] DEFAULT_OPTIONS = new OptAccess[] { oa_charset,
            oa_eol_sequence,
            oa_eol_filter,
            oa_autoflush };

    private OptAccess[] SOCKET_OPTIONS = new OptAccess[] { oa_charset,
            oa_eol_sequence,
            oa_eol_filter,
            oa_autoflush,
            oa_connect_timeout,
            oa_read_timeout,
            oa_Protocol };

    public OptAccess[] getDEFAULT_OPTIONS() {
        return DEFAULT_OPTIONS;
    }

    public OptAccess[] getSOCKET_OPTIONS() {
        return SOCKET_OPTIONS;
    }

    /*
    * --------------------------------------------------------------------------------------
    */


    /**
     * Permet de fermer tous les flux et fichiers ouverts.
     *
     * Cette méthode a une vocation interne et peut être liée à un hook.
     *
     * Si les fichiers sont déjà fermés, il ne se passe rien.
     *
     * @throws Exception
     */
    public void internal_close() throws Exception {
        // Data*Stream
        if (output != null) {
            output.close();
            output = null;
        }
        if (input != null) {
            input.close();
            input = null;
        }
        // File*Stream
        if (fileOutputStream != null) {
            fileOutputStream.close();
            fileOutputStream = null;
        }
        if (fileInputStream != null) {
            fileInputStream.close();
            fileInputStream = null;
        }
        // File
        if (file != null) {
            file = null;
        }
        // url
        if (urlConnection != null) {
            urlConnection = null;
        }
        // socket
        if (socket != null) {
            socket.close();
            socket = null;
        }
        // tcpHost
        if (tcpHost != null) {
            tcpHost = null;
        }
        // tcpIp
        if (tcpIP != null) {
            tcpIP = null;
        }
        // protocol
        if (protocol != null) {
            protocol = null;
        }
        //
        connectTimeOut = 0;
        readTimeOut = 0;
        charset = System.getProperty("file.encoding");
        eolStr = "\n";
        eol_bytes = eolStr.getBytes();
        eolFilterStr = "\r\n";
        //
        opened = false;
    }

    /**
     *Utilise un OutputStream et crée un BufferedOutputStream et un DataOutputStream à partir de celui-ci.
     * @param out
     */
    public void setOutputStream(OutputStream out) {
        output = out;
        opened = true;
    }

    /**
     * Utilise un InputStream et crée un BufferedInputStream et un DataInputStream à partir de celui-ci.
     * @param in
     */
    public void setInputStream(InputStream in) {
        input = in;
        opened = true;
    }

    /**
     *  Clé du hook...
     */
    private Object myHookKey;

    /**
     * Ajoute un hook en cas où on oublierait de fermer les fichiers et les flux...
     *
     * Ce hook sera automatiquement exécuté lors de l'arrêt de l'interpréteur, à moins
     * que le fichier soit refermé manuellement. De cette manière, les fichiers devraient
     * conserver un état stable.
     *
     */
    private void putHook() {

        final WeakReference<External_File> myself = new WeakReference<External_File>(this);
        Runnable hook = new Runnable() {

            public void run() {
                External_File me = myself.get();
                if (me != null) {
                    if (Interpreter.isDebugMode()) {
                        Interpreter.Log("Io:File Hook : close " + me + "...");
                    }
                    try {
                        me.internal_close();
                    }
                    catch (Exception e) {
                        Interpreter.Log(" -> Exception: " + e.toString());
                    }
                }
            }

        };

        myHookKey = Interpreter.supervisor_PUTHOOK(hook);
    }

    /**
     * On retire le hook...
     */
    private void removeHook() {
        Interpreter.supervisor_REMOVEHOOK(myHookKey);
        myHookKey = null;
    }


    public External_File() throws Exception {
        this.eol_bytes = this.eolStr.getBytes(charset);
        this.setOptAccessList(new OptAccessList(DEFAULT_OPTIONS));
    }

    public void setCharset(String charset) throws Exception {
        this.charset = charset;
        this.eol_bytes = this.eolStr.getBytes(charset);
    }

    public String getCharset() {
        return charset;
    }

    /*
     * La séquence EOL est ajoutée intégralement à la fin de la sortie :writeln.
     * Le dernier caractère de la séquence EOL termine la lecture de :readln.
     */

    public void setEolStr(String eol_sequence) throws Exception {
        if (eol_sequence.length() < 1)
            throw new Exception("EOL cannot be an empty string");
        this.eolStr = eol_sequence;
        this.eol_bytes = this.eolStr.getBytes(charset);
    }

    public String getEolStr() {
        return eolStr;
    }

    /*
     * Les caractères EolFilter sont retirés de la chaîne obtenue par :readln.
     * Il est donc possible que EolFilter soit une chaîne vide. Dans ce cas,
     * les caractères EOL restent inclus dans la chaîne de résultat.
     */

    public void setEolFilterStr(String eolFilterStr) {
        this.eolFilterStr = eolFilterStr;
    }

    public String getEolFilterStr() {
        return eolFilterStr;
    }

    public OutputStream getOutput() {
        return output;
    }

    public InputStream getInput() {
        return input;
    }

    public byte[] getEol_bytes() {
        return eol_bytes;
    }

    public void setOpened(boolean opened) {
        this.opened = opened;
    }

    public boolean isOpened() {
        return opened;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public String getProtocol() {
        return protocol;
    }

    public void setTcpHost(String tcpHost) {
        this.tcpHost = tcpHost;
    }

    public String getTcpHost() {
        return tcpHost;
    }

    public void setTcpPort(int tcpPort) {
        this.tcpPort = tcpPort;
    }

    public int getTcpPort() {
        return tcpPort;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    public Socket getSocket() {
        return socket;
    }

    public void setOa_Protocol(OptAccess oa_Protocol) {
        this.oa_Protocol = oa_Protocol;
    }

    public OptAccess getOa_Protocol() {
        return oa_Protocol;
    }

    public void setOa_Host(OptAccess oa_Host) {
        this.oa_Host = oa_Host;
    }

    public OptAccess getOa_Host() {
        return oa_Host;
    }

    public void setOa_Port(OptAccess oa_Port) {
        this.oa_Port = oa_Port;
    }

    public OptAccess getOa_Port() {
        return oa_Port;
    }

    public void setTcpIP(String tcpIP) {
        this.tcpIP = tcpIP;
    }

    public String getTcpIP() {
        return tcpIP;
    }

    public void setOa_IP(OptAccess oa_IP) {
        this.oa_IP = oa_IP;
    }

    public OptAccess getOa_IP() {
        return oa_IP;
    }

    public void setAutoflush(boolean autoflush) {
        this.autoflush = autoflush;
    }

    public boolean isAutoflush() {
        return autoflush;
    }


    /*****************************************************************************************************************
     *
     * Classe ExtURL privée. Cette classe offre une abstraction supplémentaire au niveau de la gestion des ressources
     * décrites sous la forme d'urls.
     *
     * Les protocoles émulés sont les suivants:
     *
     *    stdout://           : Flux de sortie standard.
     *    stdin://            : Flux d'entrée standard.
     *    stderr://           : Flux de sortie standard pour les messages d'erreur.
     *
     *    tcp://host:port     : Ouverture du port sur le host indiqué à l'aide d'un socket TCP.
     *    ssl+tcp://host:port : Idem, mais au travers d'une couche sécurisée SSL.
     *
     *    file://path         : Accès à un fichier en écriture à l'aide du protocol file.
     *
     * Les protocoles gérés par Java sont les suivants:
     *
     *    file://path         : Accès à un fichier en lecture seule.
     *
     *    jar://path          : Accès à une ressource d'une archive jar en lecture seule.
     *
     * Les protocoles assistés (c-à-d gérés par Java, mais nécessitant une abstraction supplémentaire):
     *
     *    http://...          : Support de GET, PUT et POST, ainsi que les headers HTTP.
     *    https://...         : Idem.
     *
     *    ftp://...           : Sélection du mode d'accès écriture/lecture.
     *
     */
    private class ExtURL {

        String urlStr = null;
        String protocol = null;
        String host = null;
        int port = 0;
        URL realUrl = null;

        public ExtURL(String url) throws MalformedURLException {
            this.urlStr = url;
            String u = url;
            /*
             * protocoles émulés d'abord...
             */
            if (u.equalsIgnoreCase("stdout://") || u.equalsIgnoreCase("stdin://") || u.equalsIgnoreCase("stderr://")) {
                /*
                 * les protocoles émulés stdout://, stdin:// et stderr://
                 */
                protocol = u.substring(0, u.indexOf(':')).toLowerCase();
            }
            else if (u.toLowerCase().startsWith("tcp://") || u.toLowerCase().startsWith("ssl+tcp://")) {
                /*
                 * les protocole émulés tcp://host:port et ssl+tcp://host:port
                 */
                protocol = urlStr.substring(0, urlStr.indexOf(':')).toLowerCase();
                u = u.substring(protocol.length() + 3, u.length());
                int lpp = u.lastIndexOf(':');
                if (lpp < 0 || lpp >= u.length()) {
                    throw new MalformedURLException(url);
                }
                try {
                    port = Integer.parseInt(u.substring(lpp + 1, u.length()));
                }
                catch (Exception e) {
                    throw new MalformedURLException(url);
                }
                host = u.substring(0, lpp);
            }
            else {
                /*
                 * protocoles non-émulés... On laisse donc la main au système Java...
                 */
                realUrl = new URL(urlStr);
            }
        }

        String getProtocol() {
            if (realUrl != null) {
                return realUrl.getProtocol();
            }
            else {
                return protocol;
            }
        }

        URI toURI() throws URISyntaxException {
            if (realUrl != null) {
                return realUrl.toURI();
            }
            else {
                throw new URISyntaxException(urlStr, "Cannot be converted to URI");
            }
        }

        URLConnection openConnection() throws IOException {
            return realUrl.openConnection();
        }

        String getHost() {
            if (realUrl != null) {
                return realUrl.getHost();
            }
            else {
                return host;
            }
        }

        int getPort() {
            if (realUrl != null) {
                return realUrl.getPort();
            }
            else {
                return port;
            }
        }

    }

    /**********************************************************************************************************/

    /*
     * Ouvre le fichier en mode R/W+ sur un buffer.
     *
     * (:open-buffer! buffer)
     *
     * On peut donc écrire des données dans le buffer (les nouvelles données s'ajoute
     * au buffer). Lorsqu'on lit des données, on retire des données du buffer.
     */
    public Node external_mutator_open_buffer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        SELF.require_SELF_mutable();
        if (opened) {
            throw new InterpreterException(StdErrors.extend(StdErrors.Already_used, "File already open"));
        }
        Buffer buffer = ((External_Buffer) AExtTools.getArgExternalInstance(startAt, 1, External_Buffer.class, Node.ACCESSVTYPE_MUTABLE_WRITELOCK)).getBuffer();
        setInputStream(buffer.getInputStream());
        setOutputStream(buffer.getOutputStream());
        this.setOptAccessList(new OptAccessList(this.getDEFAULT_OPTIONS()));
        // pas besoin de placer un hook...
        return null;
    }


    /*
     * Ouverture d'un fichier sur disque.
     *
     * (:open-file! PATHNAME MODE)
     *
     * Ouvre le fichier dont le chemin PATHNAME est spécifié en respectant le mode MODE:
     *  "r" = Lecture
     *  "w" = Ecriture
     *  "a" = Ajout à la fin du fichier
     */

    public Node external_mutator_open_file(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(3);
        SELF.require_SELF_mutable();
        if (opened) {
            throw new InterpreterException(StdErrors.extend(StdErrors.Already_used, "File already open"));
        }
        opened = true;
        file = new File(startAt.getSubNode(1, Node.TYPE_STRING).getString());
        String mode = startAt.getSubNode(2, Node.TYPE_STRING).getString().toLowerCase().trim();
        if (mode.equals("r")) {
            fileInputStream = new FileInputStream(file);
            input = fileInputStream;
        }
        else if (mode.equals("w")) {
            fileOutputStream = new FileOutputStream(file);
            output = fileOutputStream;
        }
        else if (mode.equals("a")) {
            fileOutputStream = new FileOutputStream(file, true);
            output = fileOutputStream;
        }
        else {
            throw new InterpreterException(StdErrors.extend(StdErrors.Invalid_parameter, "Mode not supported"));
        }
        this.setOptAccessList(new OptAccessList(this.getDEFAULT_OPTIONS()));
        /*
         * On place un hook en cas de problème ou d'oubli...
         */
        putHook();
        return null;
    }


    public Node external_mutator_open_url(Node startAt) throws Exception {
        /*
         * formes:
         * -------
         *
         *  1. (open-url "url"):
         *          Ouvre la ressource indiqué par l'url. Par défaut, celle-ci sera ouverte en lecture seule.
         *          Cependant en fonction du protocole utilisé, la ressource pourra aussi être ouverte en écriture.
         *
         *          En voici un récapitulatif:
         *          =========================
         *          tcp://host:port     -> lecture/écriture
         *          ssl+tcp://host:port -> lecture/écriture
         *          stdout://           -> écriture seule
         *          stdin://            -> lecture seule
         *          stderr://           -> écriture seule
         *
         *  2. (open-url "url" "r"):
         *          Ouvre le fichier indiqué par l'url en lecture seul.
         *
         *  3. (open-url "url" "w"):
         *          Ouvre le fichier indiqué par l'url en écriture.
         *
         *  4. (open-url "url" "rw"):
         *          Ouvre le fichier indiqué par l'url en lecture/écriture.
         *
         *  4. (open-url "url" "GET"):
         *          Ouvre le fichier indiqué par l'url en lecture en appliquant la commande GET.
         *          Le seul propotole possible est HTTP.
         *
         *  5. (open-url "url" "GET" [<"header" "value">...]):
         *          Ouvre l'url en lecture en appliquant la méthode GET avec une liste de propriétés Header.
         *          Le seul protocole possible est HTTP.
         *
         *  6. (open-url "url" "POST" "datas"/Buffer):
         *          Ouvre l'url en lecture en appliquant la méthode POST et en envoyant la chaîne datas
         *          encodée par défaut ou Buffer. Le seul protocole supporté est HTTP.
         *
         *  7. (open-url "url" "POST" "datas"/Buffer [<"header" "value">...]):
         *          Ouvre l'url en lecture en appliquant la méthode POST, la liste de propriétés Headers et
         *          en envoyant la chaîne datas ou Buffer. Le protocole supporté est HTTP.
         *
         *  8. (open-url "url" "PUT" "datas"/Buffer):
         *          Ouvre l'url en appliquant la méthode PUT et en envoyant la chaîne datas
         *          encodée par défaut ou Buffer. Le seul protocole supporté est HTTP.
         *
         *  9. (open-url "url" "PUT" "datas"/Buffer [<"header" "value">...]):
         *          Ouvre l'url en lecture en appliquant la méthode POST, la liste de propriétés Headers et
         *          en envoyant la chaîne datas ou Buffer. Le protocole supporté est HTTP.
         *
         * protocoles supportés:
         * --------------------
         *       de 1 à 3: file: jar: http: https: ftp:
         *       autres  : http: https: (notamment webdav) uniquement.
         *
         */
        if (opened) {
            throw new InterpreterException(StdErrors.extend(StdErrors.Already_used, "File already open"));
        }
        opened = true;
        startAt.isGoodArgsLength(false, 2);
        SELF.require_SELF_mutable();
        ExtURL url = new ExtURL(startAt.getSubNode(1, Node.TYPE_STRING).getString());

        /*
         * déterminer le protocol pour la suite...
         */
        protocol = url.getProtocol();
        /*
         * protocol peut être:
         *
         * - file :
         *   ----
         *     Dans ce cas, le fichier est ouvert en lecture seul.
         *     Il n'y a pas non plus ce commande comme dans le cas du http.
         *     Deuxième paramètre facultatif peut être "r" ou "w".
         *
         *     Note:
         *     ----
         *       Dans le cas du mode "w", il s'agit d'une émualation parce que java n'implémente
         *       pas l'accès en écriture au travers du protocole file:.
         *
         *     Rappel:
         *     ------
         *       Sous Windows, la forme de l'url utilisant le protocole file:// est hérité du Java.
         *       Ainsi, pour accéder à un fichier sur le disque dur C:, l'url pourra prendre les formes
         *       suivantes (c'est assez déroutant, il faut l'avouer):
         *          file:/C:\\dossier\\fichier.ext
         *          file:///C:\\dossier\\fichier.ext
         *          file:/C|\\dossier\\fichier.ext
         *          file:///C|\\dossier\\fichier.ext
         *          file:/C|/dossier/fichier.ext
         *          ou encore...
         *          file://C:/dossier/fichier.ext
         *
         *       Sous Linux et Unix, la forme est plus claire:
         *          file:///home/utilisateur/fichier
         *
         * - jar :
         *   ---
         *     Dans ce cas, le fichier d'archive est toujours ouvert en lecture seul.
         *     Il n'y a pas de commande comme en http.
         *     Deuxième paramètre facultatif possible "r".
         *
         * - http ou https :
         *   -------------
         *     Dans ce cas, il faut prendre en compte les éventuels paramètres d'en-têtes et le request.
         *     En outre, même s'il y a écriture de données vers la sortie, il est nécessaire de lire le
         *     résultat de retour dans tous les cas.
         *
         *     -> envoie de données    (request : GET, POST, PUT)
         *     <- lecture du résultat  (response).
         *
         * - ftp :
         *   ---
         *     Dans ce cas, il faut déterminer si l'url est ouverte en lecture ou en écriture.
         *     Il ne faut donc tenir compte que le deuxième  paramètre puisse être "r" ou "w".
         *
         *     Note:
         *     ----
         *       L'url d'accès ftp a la forme suivante: "ftp://<login>:<pass>@<server>/<path>".
         *
         *     Attention:
         *     ---------
         *       Si l'url est ouverte en écriture, les nouvelles données envoyées écrasent celles qui
         *       étaient précédemment dans le fichier à partir du début.
         *
         */

        String mode = null;
        Node props = null;
        Node datas = null;
        byte[] buffer = null;

        String old_c = null; // paramètres timeOut
        String old_r = null;
        int max_i = startAt.size() - 1;

        /*
         * propriétés headers...
         */
        if (startAt.elementAt(max_i).getSymbolicValue().getQType()==Node.TYPE_CLIST) {
            // il y a des propriétés header...
            // La gestion des erreurs est plus loin...
            props = startAt.getSubNode(max_i--, Node.TYPE_HASH);
        }

        /*
         * 2ième paramètres...
         */
        int i_ = 2;
        if (i_ <= max_i) {
            /*
             * il existe...
             */
            mode = startAt.getSubNode(i_++, Node.TYPE_STRING).getString().toUpperCase().trim();

            /*
             * cas des protocoles http:// et https:// ...
             */
            if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) {
                // GET, POST et PUT possible uniquement en http/https...
                if (!(mode.equals("GET") || mode.equals("POST") || mode.equals("PUT"))) {
                    throw new InterpreterException(128010, "Unsupported request methode");
                }
            }
            /*
             * cas des protocoles ftp:// et file://...
             */
            else if (protocol.equalsIgnoreCase("ftp") || protocol.equalsIgnoreCase("file")) {
                if (!(mode.equalsIgnoreCase("r") || mode.equalsIgnoreCase("w"))) {
                    throw new InterpreterException(128015, "Unsupported access methode");
                }
            }
            /*
             * cas des protocoles jar:// et stdin://
             */
            else if (protocol.equalsIgnoreCase("jar") || protocol.equalsIgnoreCase("stdin")) {
                if (!(mode.equalsIgnoreCase("r"))) {
                    throw new InterpreterException(128015, "Unsupported access methode");
                }
            }
            /*
             * cas des protocoles tcp:// et ssl+tcp://
             */
            else if (protocol.equalsIgnoreCase("tcp") || protocol.equalsIgnoreCase("ssl+tcp")) {
                if (!(mode.equalsIgnoreCase("rw"))) {
                    throw new InterpreterException(128015, "Unsupported access methode");
                }
            }
            /*
             * cas des protocoles stdout:// stderr://
             */
            else if (protocol.equalsIgnoreCase("stdout") || protocol.equalsIgnoreCase("stderr")) {
                if (!(mode.equalsIgnoreCase("w"))) {
                    throw new InterpreterException(128015, "Unsupported access methode");
                }
            }
            /*
             * autre non supporté....
             */
            else {
                throw new InterpreterException(128011, "Unsupported protocol");
            }
        }

        /*
         * des données à envoyer ? Uniquement pour http/https...
         */
        if (i_ <= max_i) {
            if (!protocol.equalsIgnoreCase("http") && !protocol.equalsIgnoreCase("https")) {
                // uniquement possible avec le protocole http/https...
                throw new InterpreterException(128016, "Unsupported request datas");
            }
            // datas...
            datas = startAt.getSubNode(i_++, Node.TYPE_STRING | Node.TYPE_BYTES | Node.VTYPE_DELEGABLE);
           
            buffer = Node.node2VBytes(datas).getBytes().getArray();
           
        }
        /*
         * gestion d'erreurs: http GET envoie des données ????
         */
        if (datas != null && mode != null && mode.equals("GET")) {
            throw new InterpreterException(128012, "GET request with data body");
        }
        /*
         * gestion d'erreur: des propriétés d'en-tête avec un autre protocol que http/https ????
         */
        if (props != null && (!protocol.equalsIgnoreCase("http") && !protocol.equalsIgnoreCase("https"))) {
            throw new InterpreterException(128013, "Cannot handle header properties in request");
        }

        try {

            /*
             * d'abord les protocoles émulés...
             */
            /**
             * cas particulier de file:// en écriture...
             *
             * Il s'agit d'une émulation...
             *
             */
            if (protocol.equalsIgnoreCase("file") && mode != null && mode.equalsIgnoreCase("w")) {
                File f = new File(url.toURI());
                output = new FileOutputStream(f);
                this.setOptAccessList(new OptAccessList(this.getDEFAULT_OPTIONS()));
                this.getOptAccessList().add(oa_Protocol);
            }
            /**
             * cas de tcp://
             */
            else if (protocol.equalsIgnoreCase("tcp")) {
                tcpHost = url.getHost();
                tcpPort = url.getPort();
                if (tcpPort < 0 || tcpPort > 65535) {
                    throw new InterpreterException(StdErrors.extend(StdErrors.Out_of_range, "" + tcpPort));
                }
                //System.out.println("host:"+tcpHost); // debug
                //System.out.println("port:"+tcpPort); // debug
                socket = new Socket(tcpHost, tcpPort);
                if (readTimeOut > 0) {
                    socket.setSoTimeout(readTimeOut);
                }
                tcpIP = socket.getInetAddress().getHostAddress();
                tcpHost = socket.getInetAddress().getHostName();
                input = socket.getInputStream();
                output = socket.getOutputStream();
                this.setOptAccessList(new OptAccessList(this.getSOCKET_OPTIONS()));
                this.getOptAccessList().set(oa_Host);
                this.getOptAccessList().set(oa_IP);
                this.getOptAccessList().set(oa_Port);
            }
            /**
             * cas de ssl+tcp://
             */
            else if (protocol.equalsIgnoreCase("ssl+tcp")) {
                tcpHost = url.getHost();
                tcpPort = url.getPort();
                if (tcpPort < 0 || tcpPort > 65535) {
                    throw new InterpreterException(StdErrors.extend(StdErrors.Out_of_range, "" + tcpPort));
                }
                SocketFactory socketFactory = SSLSocketFactory.getDefault();
                socket = socketFactory.createSocket(tcpHost, tcpPort);
                if (readTimeOut > 0) {
                    socket.setSoTimeout(readTimeOut);
                }
                tcpIP = socket.getInetAddress().getHostAddress();
                tcpHost = socket.getInetAddress().getHostName();

                input = socket.getInputStream();
                output = socket.getOutputStream();

                this.setOptAccessList(new OptAccessList(this.getSOCKET_OPTIONS()));
                this.getOptAccessList().set(oa_Host);
                this.getOptAccessList().set(oa_IP);
                this.getOptAccessList().set(oa_Port);
            }
            /**
             * cas de stdout://
             */
            else if (protocol.equalsIgnoreCase("stdout")) {
                output = System.out;
                this.setOptAccessList(new OptAccessList(this.getDEFAULT_OPTIONS()));
                this.getOptAccessList().add(oa_Protocol);
            }
            /**
             * cas de stdout://
             */
            else if (protocol.equalsIgnoreCase("stderr")) {
                output = System.err;
                this.setOptAccessList(new OptAccessList(this.getDEFAULT_OPTIONS()));
                this.getOptAccessList().add(oa_Protocol);
            }
            /**
             * cas de stdin://
             */
            else if (protocol.equalsIgnoreCase("stdin")) {
                input = System.in;
                this.setOptAccessList(new OptAccessList(this.getDEFAULT_OPTIONS()));
                this.getOptAccessList().add(oa_Protocol);
            }
            /*
             * autres protocoles...
             */
            else {
                /**
                 * sinon dans les autres cas, on ouvre réellement une connexion vers l'url...
                 */
                urlConnection = url.openConnection();
                tcpHost = url.getHost();
                tcpPort = url.getPort();
                /*
                 * timeout
                 */
                if (connectTimeOut > 0) {
                    urlConnection.setConnectTimeout(connectTimeOut);
                }
                if (readTimeOut > 0) {
                    urlConnection.setReadTimeout(readTimeOut);
                }
                /*
                 * pas de cache et toujours en lecture (par défaut)...
                 */
                urlConnection.setUseCaches(false);
                urlConnection.setDoInput(true);

                /**
                 * Typiquement HTTP
                 *
                 * Remarque: HttpsURLConnection est une sous-classe de HttpURLConnection.
                 * --------  Donc le protocole http est respecté en https.
                 */
                if (urlConnection instanceof HttpURLConnection) {
                    HttpURLConnection httpCon = (HttpURLConnection) urlConnection;

                    if (props != null) {
                        // il y a des propriétés header...
                        Hash hash=props.getHash();
                        ArrayList<String> ks=hash.keys_strings();
                        for (int i = 0; i < ks.size(); i++) {
                            String header_s = ks.get(i);
                            String value_s = Node.node2VString(hash.get(header_s)).getString();
                            Interpreter.Log("   HTTP-Header: " + header_s + " : " + value_s);
                            httpCon.setRequestProperty(header_s, value_s);
                        }
                    }

                    if (mode != null && (mode.equals("POST") || mode.equals("PUT"))) {
                        // c'est la méthode POST...
                        if (mode.equals("PUT")) {
                            Interpreter.Log("   HTTP PUT: " + url.toString());
                        }
                        else {
                            Interpreter.Log("   HTTP POST: " + url.toString());
                        }
                        urlConnection.setDoOutput(true);
                        httpCon.setRequestMethod(mode);
                        output = urlConnection.getOutputStream();

                        // envoyer...
                        output.write(buffer);
                        if (isAutoflush())
                            output.flush();
                    }

                    input = urlConnection.getInputStream();

                    this.setOptAccessList(new OptAccessList(this.getSOCKET_OPTIONS()));
                    if (tcpHost != null)
                        this.getOptAccessList().set(oa_Host);
                    if (tcpPort > 0)
                        this.getOptAccessList().set(oa_Port);

                }
                /**
                 * Autres protocoles...
                 */
                else {
                    /*
                     * par défaut méthode "r"... (r)ead...
                     */
                    if (mode == null || (mode != null && mode.equalsIgnoreCase("r"))) {
                        Interpreter.Log("   " + protocol + " read : " + url.toString());
                        input = urlConnection.getInputStream();

                    }
                    /*
                     * sinon, méthode "w"... (w)rite...
                     */
                    else {
                        Interpreter.Log("   " + protocol + " write : " + url.toString());
                        output = urlConnection.getOutputStream();

                    }
                    this.setOptAccessList(new OptAccessList(this.getSOCKET_OPTIONS()));
                    if (tcpHost != null)
                        this.getOptAccessList().set(oa_Host);
                    if (tcpPort > 0)
                        this.getOptAccessList().set(oa_Port);
                }
            }

        }
        catch (Exception e) {

            throw e;
        }
        /*
         * On place un Hook en cas où on oublie de fermer File comme il faut...
         */
        putHook();
        return null;
    }


    /*
     * (:close!)
     *
     * Ferme le fichier.
     *
     * Effectue un flush() si nécessaire.
     */

    public Node external_mutator_close(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        internal_close();
        /*
         * On retire le hook puisque les fichiers sont fermé correctement.
         */
        removeHook();
        return null;
    }

    /*
     * Retourne la quantité de données prête à lire en nombre d'octets.
     *
     */

    public Node external_available(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(input.available());
    }

    /*
     * TRUE/FALSE <- (:opened?)
     *
     * Retourne TRUE si le fichier est ouvert.
     */

    public Node external_is_opened(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(opened ? Node.TRUE: Node.FALSE);
    }

    public Node external_mutator_read_buffer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1, 2);
        SELF.require_SELF_mutable();
        Buffer buffer = new Buffer();
        buffer.setCharset(charset);
        if (startAt.size() == 2) {
            int sz = (int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber();
            byte[] buf = new byte[sz];
            int cread = input.read(buf);
            if (cread > 0) {
                buffer.write_bytes(buf, cread);
            }
            else {
                return Node.createNothing();
            }
        }
        else {
            byte[] buf = new byte[4096];
            int cread;
            while ((cread = input.read(buf)) != -1) {
                if (cread > 0) {
                    buffer.write_bytes(buf, cread);
                }
            }
            if (buffer.size() == 0 && cread == -1) {
                return Node.createNothing();
            }
        }
        External_Buffer res = new External_Buffer();
        res.setBuffer(buffer);
        return Node.createExternal(res);
    }

    public Node external_mutator_read_chunked_buffer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        Buffer buffer = new Buffer();
        buffer.setCharset(charset);
        int sz = 0;
        try {
            sz = read_int();
        }
        catch (EOFException eofe) {
            return Node.createNothing();
        }
        if (sz > 0) {
            byte[] buf = new byte[sz];
            int cread = input.read(buf);
            if (cread > 0) {
                buffer.write_bytes(buf, cread);
            }
            if (buffer.size() == 0 && cread == -1) {
                return Node.createNothing();
            }
        }
        External_Buffer res = new External_Buffer();
        res.setBuffer(buffer);
        return Node.createExternal(res);
    }

    public Node external_mutator_write_buffer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        SELF.require_SELF_mutable();
        Buffer buffer = ((External_Buffer) AExtTools.getArgExternalInstance(startAt, 1, External_Buffer.class, Node.ACCESSVTYPE_MUTABLE_WRITELOCK)).getBuffer();
        if (buffer.length() > 0) {
            byte[] buf = buffer.read_bytes();
            output.write(buf);
            output.flush();
        }
        return null;
    }

    public Node external_mutator_write_chunked_buffer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        SELF.require_SELF_mutable();
        Buffer buffer = ((External_Buffer) AExtTools.getArgExternalInstance(startAt, 1, External_Buffer.class, Node.ACCESSVTYPE_MUTABLE_WRITELOCK)).getBuffer();
        int len = buffer.length();
        write_int(len);
        if (buffer.length() > 0) {
            byte[] buf = buffer.read_bytes();
            output.write(buf);
        }
        if (isAutoflush())
            output.flush();
        return null;
    }

    public Node external_mutator_read_byte(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        int cread = -1;
        try {
            cread = input.read();
        }
        catch (EOFException e) {
            cread = -1;
        }
        if (cread == -1)
            return Node.createNothing();
        else
            return new Node(cread);
    }

    public Node external_mutator_read(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        ByteArrayOutputStream barray = new ByteArrayOutputStream();
        byte[] buf = new byte[4096];
        int cread;

        while ((cread = input.read(buf)) != -1) {
            barray.write(buf, 0, cread);
        }

        if (barray.size() == 0 && (cread == -1))
            return Node.createNothing();
        else
            return new Node(barray.toString(charset));
    }

    public Node external_mutator_readln(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        String res = "";
        ArrayList<Integer> bytes = new ArrayList<Integer>();
        int cread = -1;
        boolean cont = true;
        boolean eof = false;
        while (cont) {
            try {
                cread = input.read();
            }
            catch (EOFException e) {
                cont = false;
                eof = true;
            }
            if (cread != -1) {
                bytes.add(new Integer(cread));
                /*
                 * On arrête lorsque le dernier caractère de la séquence est trouvé.
                 */
                if (cread == eol_bytes[eol_bytes.length - 1]) {
                    cont = false;
                }
            }
            else {
                eof = true;
                cont = false;
            }
        }
        if (bytes.size() == 0 && eof)
            return Node.createNothing();
        byte[] buffer = new byte[bytes.size()];
        for (int i = 0; i < bytes.size(); i++) {
            buffer[i] = bytes.get(i).byteValue();
        }
        String res1;
        if (charset != null) {
            res1 = new String(buffer, 0, buffer.length, charset);
        }
        else {
            res1 = new String(buffer, 0, buffer.length);
        }
        //System.out.print(res1);
        for (int i = 0; i < res1.length(); i++) {
            char c = res1.charAt(i);
            /*
             * On retire les caractère eolFilter la chaîne résultante.
             */
            if (eolFilterStr.indexOf(c) < 0) {
                res = res + c;
            }
        }
        return new Node(res);
    }

    public Node external_mutator_write_byte(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        SELF.require_SELF_mutable();
        output.write((((int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber()) & 0xff));
        if (isAutoflush())
            output.flush();
        return null;
    }

    public Node external_mutator_write(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 1);
        SELF.require_SELF_mutable();

        for (int i = 1; i < startAt.size(); i++) {
            if (charset != null) {
                output.write(Node.node2VString(startAt.getSubNode(i, Node.VTYPE_VALUABLE)).getString().getBytes(charset));
            }
            else {
                output.write(Node.node2VString(startAt.getSubNode(i, Node.VTYPE_VALUABLE)).getString().getBytes());
            }

        }
        if (isAutoflush())
            output.flush();

        return null;
    }

    public Node external_mutator_flush(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        output.flush();
        return null;
    }

    public Node external_mutator_writeln(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 1);
        SELF.require_SELF_mutable();


        for (int i = 1; i < startAt.size(); i++) {
            if (charset != null) {
                output.write(Node.node2VString(startAt.getSubNode(i, Node.VTYPE_VALUABLE)).getString().getBytes(charset));
            }
            else {
                output.write(Node.node2VString(startAt.getSubNode(i, Node.VTYPE_VALUABLE)).getString().getBytes());
            }
        }

        output.write(eol_bytes);
        if (isAutoflush())
            output.flush();

        return null;
    }

    public void write_int(int v) throws IOException {
        output.write((v >>> 24) & 0xFF);
        output.write((v >>> 16) & 0xFF);
        output.write((v >>> 8) & 0xFF);
        output.write(v & 0xFF);
    }

    public int read_int() throws IOException {
        int v1 = ((int) input.read()) & 0xFF;
        int v2 = ((int) input.read()) & 0xFF;
        int v3 = ((int) input.read()) & 0xFF;
        int v4 = ((int) input.read()) & 0xFF;
        return (v1 << 24) | (v2 << 16) | (v3 << 8) | v4;
    }

    public Node external_mutator_save(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        SELF.require_SELF_mutable();
        //System.out.print(startAt);
        String serial2str = startAt.getSubNode(1, Node.VTYPE_VALUABLE).toString();
        byte[] sbuff = serial2str.getBytes("UTF-8");
        write_int(sbuff.length);
        output.write(sbuff);
        if (isAutoflush())
            output.flush();
        return null;
    }

    public Node external_mutator_save_gz(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        SELF.require_SELF_mutable();
        //System.out.print(startAt);
        String serial2str = startAt.getSubNode(1, Node.VTYPE_VALUABLE).toString();
        byte[] sbuff = serial2str.getBytes("UTF-8");
        write_int(sbuff.length);
        output.write(Tools.compress(sbuff));
        if (isAutoflush())
            output.flush();
        return null;
    }

    public Node external_mutator_load(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        int bsize;
        try {
            bsize = read_int();
        }
        catch (EOFException eofe) {
            return Node.createNothing();
        }
        byte[] sbuff = new byte[bsize];
        int verif = input.read(sbuff);
        if (verif != bsize) {
            return Node.createNothing();
        }
        String serial2str = new String(sbuff, "UTF-8");
        Interpreter interpreter = Interpreter.interpr_getNewChildInterpreter();
        interpreter.setSource(serial2str);
        interpreter.compile();
        return interpreter.execute();
    }

    public Node external_mutator_load_gz(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        SELF.require_SELF_mutable();
        int bsize;
        try {
            bsize = read_int();
        }
        catch (EOFException eofe) {
            return Node.createNothing();
        }
        byte[] sbuff = new byte[bsize];
        int verif = input.read(sbuff);
        if (verif != bsize) {
            return Node.createNothing();
        }
        String serial2str = new String(Tools.decompress(sbuff), "UTF-8");
        Interpreter interpreter = Interpreter.interpr_getNewChildInterpreter();
        interpreter.setSource(serial2str);
        interpreter.compile();
        return interpreter.execute();
    }

    public Object clone_my_self(Bivalence bival) {
        return null;
    }

    /*
     * ----------------------------------------------------------------------------
     *
     * Optimisation par cache d'instanciantion (mars 2012) rev 1.0-6321.0
     *
     * ----------------------------------------------------------------------------
     */

    private static ORef _optim_symbols_cache_ = new ORef();

    @Override
    public Object getSymbolsCache() {
        return _optim_symbols_cache_.getRef();
    }

    @Override
    public void setSymbolsCache(Object cache) {
        _optim_symbols_cache_.setRef(cache);
    }

}
TOP

Related Classes of abstrasy.libraries.io.External_File$ExtURL

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.