Package abstrasy.interpreter

Source Code of abstrasy.interpreter.ExternalTK$Name

package abstrasy.interpreter;


import abstrasy.Heap;
import abstrasy.Interpreter;
import abstrasy.Node;
import abstrasy.PCoder;
import abstrasy.SELF;
import abstrasy.Tools;

import abstrasy.externals.AExtCachable;
import abstrasy.externals.annotations.ETK_hidden;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import java.util.ArrayList;


/**
* 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
*/

public class ExternalTK {

    public ExternalTK() {
    }

    /**
     * EXTERNAL_ -> méthode externe native...
     */
    private static final String EXTERNAL_ = "external_";

    //
    // externalpc_ -> méthode à exécuter systématiquement...
    //
    //private static final String externalpc_ = "externalpc_";

    /**
     * _EXTERNAL_CLASS_ -> masque de recherche des classes enfichables...
     */
    public static final String _EXTERNAL_CLASS_ = ".External_";


    private static final Node ROOTNODE = new Node();


    /*
     * N'est plus utilisé. On la conserve à titre de documentation...
     *
     *

    private static final Node invokeE_(Object external, String methode, Object[] args) {
        Node res = null;
        Class<?> acls[] = (args != null ? new Class<?>[] { args.getClass() }: null);
        Method meth = null;
        try {
            meth = external.getClass().getDeclaredMethod(methode, acls);
        }
        catch (Exception ex0) {

            try {
                meth = external.getClass().getMethod(methode, acls);
            }
            catch (Exception ex1) {
                meth = null;
            }
        }
        if (meth != null) {
            Object obj;
            try {
                obj = meth.invoke(external, args);
            }
            catch (IllegalAccessException e) {
                obj = null;
            }
            catch (InvocationTargetException e) {
                obj = null;
            }
            if (obj != null) {
                if (obj instanceof Node) {
                    res = (Node) obj;
                }
                else if (obj instanceof String) {
                    res = new Node((String) obj);
                }
                else {
                    res = Node.createExternal(obj);
                }
            }
        }
        return res;
    }

     *
     */

    /**
     * Envoyer le message décrit dans startAt à l'objet externe.
     *
     * Le premier élément (0) de startAt doit être un symbole quoté. Ce symbole fournit
     * le nom de la méthode à appeler et les reste des éléments les éléments de argv.
     *
     * @param externalNode
     * @param startAt
     * @return
     * @throws Exception
     */
    public static Node evalMethod(Node externalNode, Node startAt) throws Exception {
        externalNode.requireNodeType(Node.TYPE_EXTERNAL);
        try {
            Object eobject = externalNode.getExternal();
            Object args[] = { startAt };
            Class acls[] = { startAt.getClass() };
            Method meth;
            Node mnode = startAt.elementAt(0);
            mnode.requireNodeType(Node.TYPE_QSYMBOL);
            String mname = PCoder.unselfing(mnode.getSymbol().getStr());
           
            try {
                meth = eobject.getClass().getMethod(Name.toExternal(mname), acls);
            }
            catch (Exception ex1) {
                ex1.printStackTrace();
                meth = null;
            }

            if (meth == null)
                throw new InterpreterException(StdErrors.extend(StdErrors.External_error, "not found " + mname + " : "+externalNode  ));

           
            Node old_self = SELF.swap(externalNode);
            Object obj = meth.invoke(eobject, args);
            SELF.restore(old_self);
           

            if (obj != null)
                if (obj instanceof Node)
                    return (Node) obj;
                else
                    return Node.createExternal(obj);
            else
                return null;

        }
        catch (Exception ex) {
            //System.out.println("***"+startAt);
            if (ex instanceof InterpreterException)
                throw ex;
            else {
                if (Interpreter.isDebugMode()) {
                    Interpreter.Log(ex.getCause().toString());
                    ex.printStackTrace();
                }
                throw new InterpreterException(StdErrors.extend(StdErrors.External_error, ex.getCause().toString()));
            }
        }

    }

    public static Node evalMethod_or_null(Node externalNode, Node startAt) throws Exception {
        externalNode.requireNodeType(Node.TYPE_EXTERNAL);
        Object eobject = externalNode.getExternal();
        Object args[] = { startAt };
        Class acls[] = { startAt.getClass() };
        Method meth;
        Node mnode = startAt.elementAt(0);
        mnode.requireNodeType(Node.TYPE_QSYMBOL);
        String mname = PCoder.unselfing(mnode.getSymbol().getStr());
        try {
            meth = eobject.getClass().getMethod(Name.toExternal(mname), acls);
        }
        catch (Exception ex1) {
            return null;
        }

        Object obj = null;
        try {
            obj = meth.invoke(eobject, args);
        }
        catch (Exception ex) {
            return null;
        }

        if (obj != null)
            if (obj instanceof Node)
                return (Node) obj;
            else
                return Node.createExternal(obj);
        else
            return null;
    }


    /**
     * Fourni la liste des slots publiques accessibles à partir de l'interface de l'objet externe.
     *
     * @param externalNode
     * @return
     */
    public static final ArrayList<String> getExternalSlots(Node externalNode) {
        ArrayList<String> abstrasyn = new ArrayList<String>();
        Class<?> cl = externalNode.getExternal().getClass();
        ArrayList<Method> mtv = new ArrayList<Method>();
        lockupAllMethodsFrom(cl, mtv);
        for (int imt = mtv.size() - 1; imt >= 0; ) {
            Method mt = mtv.get(imt--);
            String mtn = mt.getName();
            if (mtn.startsWith(EXTERNAL_) && Modifier.isPublic(mt.getModifiers()) && mt.getReturnType().isInstance(ROOTNODE))
                abstrasyn.add(Name.toAbstrasy(mtn));
        }
        return abstrasyn;
    }


    public static final boolean hasSlot(Node externalNode, String slotSymbol) {
        Object e = externalNode.getExternal();
        // s'il y a un cache...
        if (e instanceof AExtCachable) {
            String slotsStr = (String) ((AExtCachable) e).getSymbolsCache();
            // si le cache est affecté...
            if (slotsStr != null)
                return slotsStr.indexOf("("+slotSymbol+")") >= 0;
            else{
            // si le cahce est vide...
                ArrayList<String> slots = getExternalSlots(externalNode);
                slotsStr="";
                for (int i = slots.size() - 1; i >= 0; )
                        slotsStr+="("+slots.get(i--)+")";
                ((AExtCachable) e).setSymbolsCache(slotsStr);
                return slotsStr.indexOf("("+slotSymbol+")") >= 0;
            }
        }
        // en cas d'échec ou pas de cache...
        ArrayList<String> slots = getExternalSlots(externalNode);
        for (int i = slots.size() - 1; i >= 0; )
            if (slots.get(i--).equals(slotSymbol))
                return true;
        return false;

    }

    /*
     * Conservé en guise d'archive... N'est plus utilisée...
     *
     *

    public static final void createExternalAdapter(Node vobjectNode, Node fromExternalNode) throws Exception {
        //
        // place les liens de fonctions de l'object externe dans le heap du VObject fourni en argument...
        //

        Heap heap = vobjectNode.getObjHeap();
        heap.put(PCoder.EXTERNAL, fromExternalNode); // enregistrer sur le Heap...
        Object obj = fromExternalNode.getExternal();

        //
        // Optimisation Cachable Heap ?
        //
        boolean cachable = obj instanceof AExtCachable;
        ArrayList<InterfaceMapItem> heapCache = null;
        String symbolsCache = null;

        //
        // si oui, on ira beaucoup plus vite en on consommera beaucoup moins de mémoire en réutilisant directement le cache s'il y en a un.
        //
        // Estimations: - 2 x plus rapide
        //              - Economie de mémoire importante en évitant les dupplications inutiles (on réutilise les mêmes définitions pour tous
        //                les objets.
        ///
        if (cachable) {
            AExtCachable cObj = (AExtCachable) obj;
            heapCache = (ArrayList<InterfaceMapItem>) cObj.getHeapCache();
            //
            // si le cache existe, on l'utilise...
            //
            if (heapCache != null) {

                for (int i = heapCache.size(); i > 0; ) {
                    InterfaceMapItem imitem = heapCache.get(--i);
                    String l = imitem.k;
                    Node n = imitem.v;
                    heap.put(l, Heap.isImmutable(l) ? n: n.deref_unsafe());

                }
                // c'est fini déjà...
                return;
            }
            else {
                //
                // S'il n'y a pas de cache et que l'objet abstrait est cachable, on crée le cache...
                ///
                heapCache = new ArrayList<InterfaceMapItem>();
                symbolsCache = "";
            }
        }


        Class<?> cl = obj.getClass();
        ArrayList<Method> mtv = new ArrayList<Method>();
        lockupAllMethodsFrom(cl, mtv);
        Field[] dfl = cl.getDeclaredFields();
        //for (int i = 0; i < dfl.length; i++) {
        //  System.out.println("field:" + dfl[i].toString());
        //}
        for (int imt = 0; imt < mtv.size(); imt++) {
            Method mt = mtv.get(imt);

            String mtn = mt.getName();

            if (mtn.startsWith(external_)) {
                if (Modifier.isPublic(mt.getModifiers())) {
                    if (mt.getReturnType().isInstance(ROOTNODE)) {

                        String abstrasyn = ExternalTK.abstrasyNameFromExternalMethod(external_, mtn);
                        symbolsCache += " " + abstrasyn + " ";
                        //

                        // symbole -> abstrasyn
                        //Node vdef = Node.createLazy();
                        // fonction appelante -> vdef

                        //vdef.append(PRECOMP.PC_EXTCALL_).append(PRECOMP.VS_SELF_EXTERNAL_).append(Node.createSymbol(mtn).letQuoted(true));

                        // hop dans le heap...
                        //Node fn_adapt = Node.createInlineFunction(vdef).letFinal(Heap.isImmutable(abstrasyn));

                        //heap.put(abstrasyn, fn_adapt);

                        //if (heapCache != null)
                        //    heapCache.add(new InterfaceMapItem(abstrasyn, Heap.isImmutable(abstrasyn) ? fn_adapt: fn_adapt.deref()));
                        ///


                    }
                }
            }
            else if (mtn.startsWith(externalpc_)) {
                if (Modifier.isPublic(mt.getModifiers())) {
                    if (mt.getReturnType().isInstance(ROOTNODE)) {
                        String abstrasyn = ExternalTK.abstrasyNameFromExternalMethod(externalpc_, mtn);
                        // symbole -> abstrasyn
                        Node vdef = invokeE_(obj, mtn, null);
                        //
                        // Si le Node est retourné, il est assigné dans le Heap à un symbole du nom de la
                        // méthode.
                        //
                        // Pour conserver le cache, il faut que le méthode retourne un Node et que son
                        // symbole soit immuable ou immutable (une constante).
                        ///
                        if (vdef != null) {
                            // hop dans le heap...
                            heap.put(abstrasyn, vdef);
                            // si le Node est retourné, il est placé dans le cache...
                            if (heapCache != null)
                                heapCache.add(new InterfaceMapItem(abstrasyn, vdef));
                        }
                        else
                            heapCache = null; // ne pas pouvoir mettre ne cache dans ce cas...
                        if (!Heap.isImmutable(abstrasyn))
                            heapCache = null; // ne pas pouvoir mettre ne cache dans ce cas...
                    }
                }
            }
        }

        //
        // S'il y a un cache de heap en préparation, on l'enregistre...
        ///
        if (heapCache != null)
            ((AExtCachable) obj).setHeapCache(heapCache);
        if (symbolsCache != null)
            ((AExtCachable) obj).setSymbolsCache(symbolsCache);
        // c'est fini...
        return;
    }

    *
    *
    */


    public static final void lockupAllMethodsFrom(Class<?> cl, ArrayList<Method> mtv) {

        /**
         *
         * D'abord en profondeur:
         * =====================
         *    Récupérer les méthodes à partir de la classe la plus générale possible.
         **/
        Class<?> cl2 = cl.getSuperclass();
        if (cl2 != null) {
            ExternalTK.lockupAllMethodsFrom(cl2, mtv);
        }

        /**
         *
         * Envisager les spécifications par la suite.
         *
         **/

        // Récupérer les méthodes publiques
        Method[] mta = cl.getMethods();

        // pour toutes les méthodes récupérées
        for (int i = 0; i < mta.length; i++) {

            String tmp = mta[i].getName();
            if (mta[i].isAnnotationPresent(ETK_hidden.class)) {
                /*
                 * La méthode est annotée ETK_hidden.
                 * Si elle est listée, on la supprime.
                 */
                for (int j = 0; j < mtv.size(); j++) {
                    if (mtv.get(j).getName().equals(tmp)) {
                        mtv.remove(j);
                        j = mtv.size();
                    }
                }
            }
            else {
                /*
                 * Par défaut, on ajoute toutes les méthodes publiques.
                 * On vérifie toutefois de ne l'insérer qu'une seule fois dans la liste.
                 */
                boolean fnd = false;
                for (int j = 0; j < mtv.size(); j++) {
                    if (mtv.get(j).getName().equals(tmp)) {
                        fnd = true;
                        j = mtv.size();
                    }
                }
                if (!fnd) {
                    mtv.add(mta[i]);
                }
            }
        }
    }

    /*
     * Retirée (l.bruninx, 2012-07-25)
     *
    
    public static String buildInExternalName(Node startAt, String extName) throws Exception {
        String res = null;
        try {
            Package rootpack = startAt.getClass().getPackage();
             //
             //  Class extclass = Class.forName(rootpack.getName() + _External_ + extName);
             //
             // remplacé par :
             //
             //
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            Class<?> extclass = loader.loadClass(rootpack.getName() + _EXTERNAL_CLASS_ + extName);
             //
             //
             //
            res = extclass.getName();
        }
        catch (Exception ex) {
            if (Interpreter.isDebugMode()) {
                Interpreter.Log(ex.getMessage());
                ex.printStackTrace();
            }
            throw new InterpreterException(StdErrors.extend(StdErrors.External_error, "Can not load " + _EXTERNAL_CLASS_ + extName));
        }
        return res;
    }
   
     *
     */

    public static Node makeExternal(String extName) throws Exception {
        Node res = null;
        try {
            /**
             *  Class extclass = Class.forName(extName);
             *
             * remplacé par :
             *
             */
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            Class<?> extclass = loader.loadClass(extName);
            /**
             *
             */

            res = Node.createExternal(extclass.newInstance());
        }
        catch (Exception ex) {
            if (ex instanceof SilentException) {
                Interpreter.Log("SILENT EXCEPTION [makeExternal]");
                throw new SilentException();
            }

            if (Interpreter.isDebugMode()) {
                ex.printStackTrace();
            }
            throw new InterpreterException(StdErrors.External_error);
        }
        return res;
    }

    public static final class Name {

        public static final String toAbstrasy(String externalName) {
            String mn0 = externalName.substring(EXTERNAL_.length(), externalName.length());
            mn0 = mn0.replace('_', '-');
            mn0 = Tools.replaceCSeq(mn0, "---", "#"); // insérer inhibiteur...
            mn0 = Tools.replaceCSeq(mn0, "--", "_");
            if (mn0.startsWith("is-")) {
                mn0 = mn0.substring(3, mn0.length()) + "?";
            }
            else if (mn0.startsWith("mutator-")) {
                mn0 = mn0.substring(8, mn0.length()) + "!";
            }
            mn0 = Tools.replaceCSeq(mn0, "#", ""); // enlever inhibiteur...
            return mn0;
        }

        public static final String toExternal(String abstrasyName) {
            String mn0 = abstrasyName;
            boolean is_ = mn0.charAt(mn0.length() - 1) == '?';
            if (is_)
                mn0 = mn0.substring(0, mn0.length() - 1);
            boolean static_ = mn0.charAt(mn0.length() - 1) == '!';
            if (static_)
                mn0 = mn0.substring(0, mn0.length() - 1);
            mn0 = Tools.replaceCSeq(mn0, "_", "--");
            mn0 = mn0.replace('-', '_');
            if (is_)
                mn0 = "is_" + mn0;
            if (static_)
                mn0 = "mutator_" + mn0;
            //System.out.println("*"+mn0+"*");
            return EXTERNAL_ + mn0;
        }

    }

}
TOP

Related Classes of abstrasy.interpreter.ExternalTK$Name

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.