All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.dev.component.Resolver Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

package com.tangosol.dev.component;


import java.io.IOException;

import java.util.Iterator;

import com.tangosol.dev.assembler.ClassFile;

import com.tangosol.util.Base;
import com.tangosol.util.ErrorList;


/**
* A Component Definition Resolver instantiates and resolves a Component
* Definition based on a name.  The complexities associated with derivation
* are isolated to this class.
*
* (The complexities associated with modification are isolated to the
* repository type handler for Component Definitions.)
*
* A large number of dependencies must be resolved in order to resolve a
* Component Definition.  These dependencies include each Component Definition
* (CD) and Java Class Signature (JCS) which are used to compose the Component
* being resolved.
*
* The trait hierarchy and associated resolve dependencies within a Component
* Definition are as follows:
*
*   Trait/Attribute         Derivation Resolve Dependency
*   ----------------------  -----------------------------
*   Component
*     extends               CD  - super (0/1)
*     implements            JCS - interface (0+)
*     dispatches            JCS - interface (0+)
*     Integration
*     Property
*       Component           CD  - complex property (0/1)
*         ...
*     Behavior
*       ReturnValue
*       Parameter
*       Throwee
*       Implementation
*     Category
*     Component             CD  - child (0+)
*       ...
*
* The process of resolving a Component Definition can be described as:
*   1.  The super for the Component Definition to resolve is loaded
*       and, if it is a derivation, it is resolved (which recursively
*       executes this same process starting with number 1).
*   2.  The Resolver requests the Component Definition to resolve, passing
*       the resolved super and itself (since it implements the Loader
*       interface).
*   3.  The Component Definition resolves as much as possible, which is
*       itself and any of its children that correspond to the children
*       of its super.
*   4.  For children which do not derive from children of its super, the
*       Component Definition requests the supplied loader (i.e. the
*       Resolver) to load the Component Definitions from which the children
*       derive.  The Component Definition then requests the children to
*       resolve (basically recursing to step 2) passing on the Loader
*       interface (i.e. the Resolver).
*   5.  The Component Definition resolves its other dependent traits,
*       such as complex Properties, interfaces, and integration.  (The
*       order of this particular step is not important; it may be performed
*       before step 3.)
*
* Consider the persistent Component Definitions:
*
* Name   Mode          Super  Description                         Stands For
* -----  ------------  -----  ----------------------------------  -----------
* B      Resolved      n/a    The base component                  B=Base
* B.C    Derivation    B      An aggregable component             C=Containable
* B.D    Derivation    B      An aggregating component            D=Derived
* B.D$I  Derivation    B.C    An aggregated component within B.D  I=Inner
*
* The pseudo-operations for the top-down construction of the resolved
* Component Definition "D" are as follows:
*
* 1) The "user" requests the Component Definition by the name of "D":
*      resolver = new Resolver(loader);
*      CD = resolver.loadComponent("D", fReadOnly, errlist)
* 2) The Resolver requests its Loader to instantiate D
* 3) The Loader returns the requested Component Definition to the Resolver;
*    note that D is a derivation-mode Component Definition
* 4) The Resolver determines that B is required to resolve D, and requests
*    itself to load B
* 5) The Resolver requests its Loader to instantiate B
* 6) The Loader returns the requested Component Definition to the Resolver;
*    note that B is a resolved Component Definition
* 7) The Resolver returns B to itself (see step 4)
* 8) The Resolver requests the Component Definition D to resolve itself,
*    passing B as the super and itself (Resolver) as the Loader to allow
*    the Component Definition to load any other dependencies
* 9) D applies itself to B, thus resolving D (but not its children)
* 10) D attempts to resolve its children using the children of B, but there
*     are no matches (in this case, B has no children at all)
* 11) D iterates through the remaining unresolved children and, for each
*     that derives from a global Component Definition, D requests its
*     Loader (i.e. the Resolver) to load the required super Component.
*     In this case, D requests C to be loaded in order to resolve I.
* 12) The Resolver requests its Loader to instantiate C (see step 2)
* 13) The Loader returns the requested Component Definition to the
*     Resolver; note that C is a derivation-mode Component Definition
* 14) The Resolver determines that B is required to resolve C, and requests
*     itself to load B
* 15) B is returned from the Resolver's cache (it was placed there between
*     steps 6 & 7)
* 16) The Resolver requests C to resolve itself (see step 8), passing
*     itself as the Loader
* 17) C resolves itself; it has no child Component Definitions
* 18) The Resolver returns C to D (closing step 11)
* 19) D requests its child I to resolve, passing the resolved C and the
*     Loader (i.e. the Resolver)
* 20) I resolves itself; it has no child Component Definitions; this
*     completes the resolve of D begun in step 8
* 21) The Resolver returns D to the "user"
*
* @version 1.00, 02/04/98
* @author  Cameron Purdy
*/
public class Resolver
        extends    Base
        implements Constants, Loader
    {
    // ----- construction ---------------------------------------------------

    /**
    * Construct a Resolver given a loader.
    *
    * @param loader  the Loader object to use to load resolved or derived
    *                Component Definitions (plus JCS's); note that
    *                this loader must NOT return modifications
    */
    public Resolver(Loader loader)
        {
        this(loader, null);
        }

    /**
    * Construct a Resolver given a loader and a destination package for
    * relocatable classes.
    *
    * @param loader  the Loader object to use to load resolved or derived
    *                Component Definitions (plus JCS's); note that
    *                this loader must NOT return modifications
    * @param sPkg    the package name to use for relocatable classes
    */
    public Resolver(Loader loader, String sPkg)
        {
        m_loader = loader;

        if (sPkg != null)
            {
            m_sPkg      = sPkg;
            m_relocator = new ClassFile.Relocator(sPkg);
            }
        }


    // ----- Loader interface -----------------------------------------------

    /**
    * Load the specified Component.
    *
    * @param sName      fully qualified Component Definition name
    * @param fReadOnly  true if the loaded component will be read-only
    * @param errlist    the ErrorList object to log any derivation/
    *                   modification errors to
    *
    * @return the specified Component Definition or null
    *
    * @exception ComponentException  if an unrecoverable error occurs
    */
    public Component loadComponent(String sName, boolean fReadOnly, ErrorList errlist)
            throws ComponentException
        {
        // load the component
        Component cd = m_loader.loadComponent(sName, true, errlist);
        if (cd != null)
            {
            // make sure the component is resolved
            switch (cd.getMode())
                {
                case RESOLVED:
                    // gg: 2001.4.25 JCS Interface should be stored as derivation
                    if (cd.isInterface())
                        {
                        throw new ComponentException(CLASS + ".loadComponent:  " + 
                            "Interface " + sName + " should be a derivation");
                        }
                    if (!fReadOnly)
                        {
                        // the only resolved component is "Root"
                        // the only resolved signature is "java.lang.Object"
                        cd.setModifiable(true);
                        }
                    break;
                    
                case DERIVATION:
                    Component cdSuper = cd.isInterface()
                        ? new Component(null, Component.SIGNATURE, BLANK)
                        : loadComponent(cd.getSuperName(), true, errlist);

                    if (cdSuper == null)
                        {
                        throw new ComponentException("Failed to load the super component: \"" +
                            cd.getSuperName() + "\" of component \"" + sName + '"');
                        }

                    if (Trait.DEBUG)
                        {
                        out();
                        out("***Resolver*** Component Super before resolve:");
                        cdSuper.dump();
                        out();
                        out("***Resolver*** Component Delta before resolve:");
                        cd.dump();
                        }

                    cd = cdSuper.resolve(cd, this, errlist);
                    if (Trait.DEBUG)
                        {
                        out();
                        out("***Resolver*** Component Derived after resolve:");
                        cd.dump();
                        }

                    // finish resolve processing
                    cd.finalizeResolve(this, errlist);
                    if (Trait.DEBUG)
                        {
                        out();
                        out("***Resolver*** Component Derived after finalizeResolve:");
                        cd.dump();
                        }

                    if (fReadOnly)
                        {
                        // default is: Modifiable == true
                        cd.setModifiable(false);
                        }
                    
                    break;

                case MODIFICATION:
                case INVALID:
                default:
                    throw new ComponentException(CLASS + ".loadComponent:  " + 
                        "Loader returned invalid mode \"" + sName + "\"(" +
                        (cd.getMode() == MODIFICATION ? "MODIFICATION" : "INVALID")
                        + ")");
                }
            }
        
        return cd;
        }

    /**
    * Load the specified Class Signature by delegating to the Resolver's
    * loader.
    *
    * @param sName    qualified Java Class Signature (JCS) name
    *
    * @return the specified Class Signature
    *
    * @exception ComponentException  if an unrecoverable error occurs
    */
    public Component loadSignature(String sName)
            throws ComponentException
        {
        // load the signature
        Component signature = m_loader.loadSignature(sName);
        if (signature != null)
            {
            // make sure the signature is resolved
            switch (signature.getMode())
                {
                case RESOLVED:
                    // java.lang.Object is the only resolved one
                    break;
                    
                case DERIVATION:
                    String    sSuperName = signature.getSuperName();
                    Component signatureSuper;
                    if (sSuperName.length() == 0)
                        {
                        // this is the case for interface JCSes that extend another interface
                        signatureSuper = new Component(null, Component.SIGNATURE, BLANK);
                        }
                    else
                        {
                        // this is all non-interface classes except java.lang.Object
                        signatureSuper = loadSignature(sSuperName);
                        if (signatureSuper == null)
                            {
                            throw new ComponentException(CLASS + ".loadSignature:  " + 
                                "Failure to load the super " + signature.getSuperName() +
                                " for class " + sName);
                            }
                        }
                    Component signatureDelta = signature;
                    if (Trait.DEBUG)
                        {
                        out();
                        out("***Resolver*** Signature Super before resolve:");
                        signatureSuper.dump();
                        out();
                        out("***Resolver*** Signature Delta before resolve:");
                        signatureDelta.dump();
                        }
                    
                    ErrorList errlist = new ErrorList();
                    signature = signatureSuper.resolve(signatureDelta, this, errlist);
                    if (Trait.DEBUG)
                        {
                        out();
                        out("***Resolver*** Signature Derived after resolve:");
                        signature.dump();
                        }
                    
                    // an error during JCS resolution is "fatal"
                    if (!errlist.isEmpty())
                        {
                        throw new ComponentException(formatErrorList(sName, errlist, false));
                        }
                    
                    // finish resolve processing
                    signature.finalizeResolve(this, errlist);
                    if (Trait.DEBUG)
                        {
                        out();
                        out("***Resolver*** Signature Derived after finalizeResolve:");
                        signature.dump();
                        }
                    
                    // an error during JCS finalize resolution is also "fatal"
                    if (!errlist.isEmpty())
                        {
                        throw new ComponentException(formatErrorList(sName, errlist, true));
                        }
                    
                    break;
                    
                case MODIFICATION:
                case INVALID:
                default:
                    throw new ComponentException(CLASS + ".loadSignature:  " + 
                        "Loader returned invalid mode \"" + sName + "\"(" +
                        (signature.getMode() == MODIFICATION ? "MODIFICATION" : "INVALID")
                        + ")");
                }
            }
        
        return signature;
        }
    
    private String formatErrorList(String sName, ErrorList errlist, boolean fFinalize)
        {
        StringBuffer sb = new StringBuffer();
        if (fFinalize)
            {
            sb.append("Finalize ");
            }
        sb.append("Resolve of Java Class Signature ");
        sb.append(sName);
        sb.append(" contains ");
        sb.append(errlist.size());
        sb.append(" errors:");
        for (Iterator iter = errlist.iterator(); iter.hasNext(); )
            {
            sb.append("\n    ");
            sb.append(iter.next().toString());
            }
        return sb.toString();
        }
    
    /**
    * Load the original (before any customization takes place) Java Class.
    *
    * @param sName  fully qualified Java Class name
    *
    * @return the specified Class structure
    *
    * @exception ComponentException  if an unrecoverable error occurs
    */
    public ClassFile loadOriginalClass(String sName)
            throws ComponentException
        {
        return m_loader.loadOriginalClass(sName);
        }

    /**
    * Load the specified generated Java Class.
    *
    * @param sName  fully qualified Java Class name
    *
    * @return the specified Class structure
    *
    * @exception ComponentException  if an unrecoverable error occurs
    */
    public ClassFile loadClass(String sName)
            throws ComponentException
        {
        ClassFile clz = m_loader.loadClass(sName);

        if (m_sPkg != null)
            {
            // check if the requested class is in the relocatable package
            if (clz == null && sName.startsWith(m_sPkg))
                {
                sName = ClassFile.Relocator.PACKAGE + sName.substring(m_sPkg.length());
                clz   = m_loader.loadClass(sName);
                }

            if (clz != null)
                {
                clz.resolve(m_relocator);
                }
            }

        return clz;
        }

    /**
    * Load the source code for the specified (original) Java class.
    *
    * @param sName  fully qualified Java Class name
    *
    * @return the specified Java source code as a String
    *
    * @exception IOException  if an unrecoverable error occurs
    */
    public String loadJava(String sName)
            throws IOException
        {
        String sScript = m_loader.loadJava(sName);

        // check if the requested Java source is in the relocatable package
        if (sScript == null && m_sPkg != null && sName.startsWith(m_sPkg))
            {
            sName   = ClassFile.Relocator.PACKAGE + sName.substring(m_sPkg.length());
            sScript = m_loader.loadJava(sName);
            }

        return sScript;
        }

    /**
    * Load the original (before any customization takes place) resource.
    *
    * @param sName  fully qualified resource name
    *
    * @return the specified resource as a byte array
    *
    * @exception IOException  if an unrecoverable error occurs
    */
    public byte[] loadOriginalResource(String sName)
            throws IOException
        {
        return m_loader.loadOriginalResource(sName);
        }

    /**
    * Load the Resource Signature.
    *
    * @param sName  fully qualified resource name
    *
    * @return the specified Resource Signature as a byte array
    *
    * @exception IOException  if an unrecoverable error occurs
    */
    public byte[] loadResourceSignature(String sName)
            throws IOException
        {
        return m_loader.loadResourceSignature(sName);
        }

    /**
    * Load the generated resource.
    *
    * @param sName  fully qualified resource name
    *
    * @return the specified resource as a byte array
    *
    * @exception IOException  if an unrecoverable error occurs
    */
    public byte[] loadResource(String sName)
            throws IOException
        {
        byte[] ab = m_loader.loadResource(sName);

        // check if the requested resource is in the relocatable package
        if (ab == null && m_sPkg != null && sName.startsWith(m_sPkg))
            {
            sName = ClassFile.Relocator.PACKAGE + sName.substring(m_sPkg.length());
            ab    = m_loader.loadResource(sName);
            }

        return ab;
        }

    /**
    * Provide a short human-readable description of the trait.
    *
    * @return a human-readable description of this trait
    */
    public String toString()
        {
        return CLASS + '(' + m_loader + ')';
        }    
    
    // ----- data members ---------------------------------------------------

    /**
    * The name of this class.
    */
    private static final String CLASS = "Resolver";

    /**
    * The Loader which the Resolver uses to access the "persistent storage"
    * of CD's, and JCS's.
    */
    private Loader m_loader;

    /**
    * The package for relocatable classes.
    */
    private String m_sPkg;

    /**
    * The relocator for relocatable classes.
    */
    private ClassFile.Relocator m_relocator;
    }






© 2015 - 2024 Weber Informatics LLC | Privacy Policy