Package org.codehaus.aspectwerkz

Source Code of org.codehaus.aspectwerkz.AspectSystem

/**************************************************************************************
* Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved.                 *
* http://aspectwerkz.codehaus.org                                                    *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the LGPL license      *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package org.codehaus.aspectwerkz;

import gnu.trove.TIntObjectHashMap;
import org.codehaus.aspectwerkz.aspect.management.AspectManager;
import org.codehaus.aspectwerkz.connectivity.Invoker;
import org.codehaus.aspectwerkz.connectivity.RemoteProxy;
import org.codehaus.aspectwerkz.connectivity.RemoteProxyServer;
import org.codehaus.aspectwerkz.definition.SystemDefinition;
import org.codehaus.aspectwerkz.exception.DefinitionException;
import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
import org.codehaus.aspectwerkz.expression.CflowExpressionVisitorRuntime;
import org.codehaus.aspectwerkz.expression.ExpressionContext;
import org.codehaus.aspectwerkz.expression.PointcutType;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.reflect.MethodInfo;

import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Properties;

/**
* Represents the aspect runtime system.<br/> Manages the different parts of the runtime system and provides and API to
* access and manage the system.<br/>
* <p/>
* There is an AspectSystem per ClassLoader. An AspectSystem is aware of the classloader hierarchy and reflects it by
* gathering the AspectManager, which represents a single &lt;system ..&gt; entry.
* <p/>
* When an instance of an AspectSystem is created (perClassLoader), it checks for existence of previous AspectManager
* defined in parent ClassLoader. AspectManager are shared among AspectSystem as shown below:<br/> </p>
* <pre>
*          [0d, 1d, 2d]  (3 SystemDefs, all defined in this classloader)
*                  /   \
* [0r, 1r, 2r, 3d]      \  (3 reused, one more defined)
*                     [0r, 1r, 2r, 3d]  (one more defined, not the same)
* </pre>
* </p> This composition strategy allow to avoid global static repository, but is tight to following ClassLoader parent
* hierarchy. </p> If an AspectManager is added at runtime, it should be added in the whole child hierarchy. TODO </p>
* <p/>
* TODO: caution when addding a new SystemDefinition in between. TODO: move the remote proxy elsewhere unless defining
* classloader is needed.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r</a>
* @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
*/
public final class AspectSystem {
    /**
     * The path to the remote proxy server config file.
     */
    private static final boolean START_REMOTE_PROXY_SERVER = "true".equals(
            java.lang.System.getProperty(
                    "aspectwerkz.remote.server.run",
                    "false"
            )
    );

    /**
     * ClassLoader defining this AspectSystem
     */
    private final ClassLoader m_classLoader;

    /**
     * The aspect managers in the order of the hierarchy
     */
    private AspectManager[] m_aspectManagers;

    /**
     * Holds a list of the cflow join points passed by the control flow of the current thread.
     *
     * @TODO: I think we need to use a static TL - need test coverage
     */
    private final ThreadLocal m_cflowStack = new ThreadLocal();

    /**
     * The remote proxy server instance.
     */
    private RemoteProxyServer m_remoteProxyServer = null;

    /**
     * Should NEVER be invoked by the user. Use <code>SystemLoader.getSystem(uuid)</code> to retrieve the system.
     * <p/>
     * Creates a new AspectWerkz AOPC system instance.
     * <p/>
     *
     * @param loader      the classloader defining the system
     * @param definitions the ordered SystemDefinitions for the system (whole hierarchy)
     */
    AspectSystem(ClassLoader loader, final List definitions) {
        m_classLoader = loader;
        m_aspectManagers = new AspectManager[definitions.size()];

        // assert uuid are unique in the ClassLoader hierarchy
        assertUuidUniqueWithinHierarchy(definitions);

        // copy the AspectManagers from the parent ClassLoader AspectSystem
        if ((loader != null) && (loader.getParent() != null)) {
            AspectManager[] parentAspectManagers = SystemLoader.getSystem(loader.getParent()).getAspectManagers();
            System.arraycopy(parentAspectManagers, 0, m_aspectManagers, 0, parentAspectManagers.length);
        }

        // note: we should be able to go directly to the correct index instead of this loop and check
        for (int i = 0; i < m_aspectManagers.length; i++) {
            SystemDefinition def = (SystemDefinition)definitions.get(i);
            String uuid = def.getUuid();

            // check if the SystemDefinition comes from a parent AspectSystem before adding it
            AspectManager aspectManager = null;
            try {
                aspectManager = getAspectManager(uuid);
            } catch (DefinitionException e) {
                ;
            }
            if (aspectManager == null) {
                // new def defined in THIS CL and not a parent one
                aspectManager = new AspectManager(this, def);

                //System.out.println("created AspectManager = " + uuid + ": " + aspectManager);
            } else {
                //System.out.println("reused AspectManager = " + uuid + ": " + aspectManager);
                continue;
            }
            m_aspectManagers[i] = aspectManager;
        }
        if (START_REMOTE_PROXY_SERVER) {
            startRemoteProxyServer();
        }
    }

    /**
     * Returns the classloader which defines this AspectSystem
     *
     * @return the classloader which defines this AspectSystem
     */
    public ClassLoader getDefiningClassLoader() {
        return m_classLoader;
    }

    /**
     * Returns an AspectManager by its index. The index are stable when the ClassLoader hierarchy is crossed from top to
     * bottom
     *
     * @param aspectManagerIndex
     * @return AspectManager, or throw an IndexOutOfBoundException
     */
    public AspectManager getAspectManager(int aspectManagerIndex) {
        return m_aspectManagers[aspectManagerIndex];
    }

    /**
     * Returns an AspectManager by its uuid
     *
     * @param uuid
     * @return AspectManager
     * @throws DefinitionException (runtime exception) if not found
     */
    public AspectManager getAspectManager(final String uuid) {
        // Note: uuid is assumed to be unique within an AspectSystem
        for (int i = 0; i < m_aspectManagers.length; i++) {
            AspectManager aspectManager = m_aspectManagers[i];

            // the null check makes sense only in the flow of <init>
            if ((aspectManager != null) && aspectManager.getUuid().equals(uuid)) {
                return aspectManager;
            }
        }
        throw new DefinitionException("no AspectManager with system id " + uuid + " in " + m_classLoader);
    }

    /**
     * Initializes the system. The initialization needs to be separated from the construction of the manager, and is
     * triggered by the runtime system
     */
    public void initialize() {
        for (int i = 0; i < m_aspectManagers.length; i++) {
            m_aspectManagers[i].initialize();
        }
    }

    /**
     * Returns the aspect managers for this system.
     *
     * @return the aspect managers
     */
    public AspectManager[] getAspectManagers() {
        return m_aspectManagers;
    }

    /**
     * Registers entering of a control flow join point.
     *
     * @param pointcutType the pointcut type
     * @param methodInfo   the method info
     * @param withinInfo   the within info
     */
    public void enteringControlFlow(
            final PointcutType pointcutType, final MethodInfo methodInfo,
            final ClassInfo withinInfo) {
        if (pointcutType == null) {
            throw new IllegalArgumentException("pointcut type can not be null");
        }
        if (methodInfo == null) {
            throw new IllegalArgumentException("method info can not be null");
        }
        TIntObjectHashMap cflows = (TIntObjectHashMap)m_cflowStack.get();
        if (cflows == null) {
            cflows = new TIntObjectHashMap();
        }
        ExpressionContext expressionContext = new ExpressionContext(pointcutType, methodInfo, withinInfo);
        cflows.put(expressionContext.hashCode(), expressionContext);
        m_cflowStack.set(cflows);
    }

    /**
     * Registers exiting from a control flow join point.
     *
     * @param pointcutType the pointcut type
     * @param methodInfo   the method info
     * @param withinInfo   the within info
     */
    public void exitingControlFlow(
            final PointcutType pointcutType, final MethodInfo methodInfo,
            final ClassInfo withinInfo) {
        if (pointcutType == null) {
            throw new IllegalArgumentException("pointcut type can not be null");
        }
        if (methodInfo == null) {
            throw new IllegalArgumentException("method info can not be null");
        }
        TIntObjectHashMap cflows = (TIntObjectHashMap)m_cflowStack.get();
        if (cflows == null) {
            return;
        }
        ExpressionContext ctx = new ExpressionContext(pointcutType, methodInfo, withinInfo);
        cflows.remove(ctx.hashCode());
        m_cflowStack.set(cflows);
    }

    /**
     * Checks if we are in the control flow of a join point picked out by a specific pointcut expression.
     *
     * @param expression        the cflow expression runtime visitor
     * @param expressionContext the join point expression context whose pointcut contains cflows sub expression(s)
     * @return boolean
     */
    public boolean isInControlFlowOf(
            final CflowExpressionVisitorRuntime expression, ExpressionContext expressionContext) {
        if (expression == null) {
            throw new IllegalArgumentException("expression can not be null");
        }
        TIntObjectHashMap cflows = (TIntObjectHashMap)m_cflowStack.get();
        if (cflows == null) {
            // we still need to evaluate the expression to handle "NOT cflow"
            cflows = new TIntObjectHashMap();
        }
        if (expression.matchCflowStack(cflows.getValues(), expressionContext)) {
            return true;
        }
        return false;
    }

    /**
     * Starts up the remote proxy server.
     *
     * @TODO: option to shut down in a nice way?
     */
    private void startRemoteProxyServer() {
        m_remoteProxyServer = new RemoteProxyServer(ContextClassLoader.getLoader(), getInvoker());
        m_remoteProxyServer.start();
    }

    /**
     * Returns the Invoker instance to use.
     *
     * @return the Invoker
     */
    private Invoker getInvoker() {
        Invoker invoker;
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream(java.lang.System.getProperty("aspectwerkz.resource.bundle")));
            String className = properties.getProperty("remote.server.invoker.classname");
            invoker = (Invoker)ContextClassLoader.getLoader().loadClass(className).newInstance();
        } catch (Exception e) {
            invoker = getDefaultInvoker();
        }
        return invoker;
    }

    /**
     * Returns the default Invoker.
     *
     * @return the default invoker
     */
    private Invoker getDefaultInvoker() {
        return new Invoker() {
            public Object invoke(
                    final String handle, final String methodName, final Class[] paramTypes,
                    final Object[] args, final Object context) {
                Object result;
                try {
                    final Object instance = RemoteProxy.getWrappedInstance(handle);
                    final Method method = instance.getClass().getMethod(methodName, paramTypes);
                    result = method.invoke(instance, args);
                } catch (Exception e) {
                    throw new WrappedRuntimeException(e);
                }
                return result;
            }
        };
    }

    /**
     * Checks uuid unicity within the list. Throw a DefinitionException on failure.
     *
     * @param definitions
     * @TODO AVAOPC algo is crapped, check earlier and avoid exception but do a WARN (in SysDefContainer)
     */
    private static void assertUuidUniqueWithinHierarchy(final List definitions) {
        for (int i = 0; i < definitions.size(); i++) {
            SystemDefinition systemDefinition = (SystemDefinition)definitions.get(i);
            for (int j = 0; j < definitions.size(); j++) {
                if (j == i) {
                    continue;
                }
                SystemDefinition systemDefinition2 = (SystemDefinition)definitions.get(j);
                if (systemDefinition2.getUuid().equals(systemDefinition.getUuid())) {
                    throw new DefinitionException(
                            "UUID is not unique within hierarchy: " + systemDefinition.getUuid()
                    );
                }
            }
        }
    }

    /**
     * Propagates the aspect managers.
     *
     * @param block
     * @param blockSizeBefore
     */
    public void propagateAspectManagers(final AspectManager[] block, final int blockSizeBefore) {
        AspectManager[] newAspectManagers = new AspectManager[m_aspectManagers.length
                                                              + (block.length - blockSizeBefore)];
        System.arraycopy(block, 0, newAspectManagers, 0, block.length);
        if (blockSizeBefore < m_aspectManagers.length) {
            System.arraycopy(
                    m_aspectManagers, blockSizeBefore, newAspectManagers, block.length + 1,
                    m_aspectManagers.length - blockSizeBefore
            );
        }
        m_aspectManagers = newAspectManagers;
    }
}
TOP

Related Classes of org.codehaus.aspectwerkz.AspectSystem

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.