/******************************************************************************* * Copyright (c) 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /* */ package org.eclipse.jem.internal.proxy.core; import java.util.EventObject; import java.util.logging.Level; /** * This is a proxy for an IExpression evaluation value. It is used as a place holder proxy value for result of an expression, and * then the value can be used in a later expression, or at the end, it can callback and return a proxy in the IDE * side in a callback for usage later on outside of the IExpression. * <p> * After receiving the resolved event, listeners should not hold onto the ExpressionProxy because it would then be invalid. At that * point they should instead hold onto the resolved bean proxy. * * @see org.eclipse.jem.internal.proxy.core.IExpression#assignExpressionProxy() * @see org.eclipse.jem.internal.proxy.core.IExpression#createExpressionProxyExpression(int, ExpressionProxy) * @since 1.1.0 */ public class ExpressionProxy implements IProxy { public ProxyFactoryRegistry getProxyFactoryRegistry() { return getExpression().getRegistry(); } /** * The event object for the resolved event of the proxy listener. * <p> * The source will be the ExpressionProxy that is being resolved. * @since 1.1.0 */ public static class ProxyEvent extends EventObject { /** * Comment for <code>serialVersionUID</code> * * @since 1.1.0 */ private static final long serialVersionUID = -2305781662465107377L; private final IBeanProxy proxy; /** * @param source the expression proxy for the event. * @param proxy the bean proxy the expression proxy (source) resolved to. * * @since 1.1.0 */ public ProxyEvent(ExpressionProxy source, IBeanProxy proxy) { super(source); this.proxy = proxy; } /** * Construct the event with no proxy. Used for not resolved and void. * @param source * * @since 1.1.0 */ public ProxyEvent(ExpressionProxy source) { this(source, null); } /** * Get the proxy value that the expression proxy (source) resolved to. * @return * * @since 1.1.0 */ public IBeanProxy getProxy() { return proxy; } } /** * Listener for expression proxy events. * * @since 1.1.0 */ public interface ProxyListener { /** * The expression proxy has been resolved. The event contains the resolved proxy. * At this point, any listeners should no longer hold onto the ExpressionProxy * because it is now invalid. They should hold onto the resolved bean proxy instead. * * @param event * * @since 1.1.0 */ public void proxyResolved(ProxyEvent event); /** * This is called for ExpressionProxies that have a callback listener, but the proxy * was never resolved. This means that the expression that assigns to the proxy was * not executed. In this case the event does not have a bean proxy in it. * * @param event * * @since 1.1.0 */ public void proxyNotResolved(ProxyEvent event); /** * This is called for ExpressionProxies that were assigned to an expression that * had a <code>VOID</code> return type. This is usually for method invocations that * have a void return type. In this case the event does not have a bean proxy in it. * @param event * * @since 1.1.0 */ public void proxyVoid(ProxyEvent event); } /** * An implementation of ProxyListener that does nothing. It can be * used as a superclass for individual listeners that are only interested * in some of the events. * * @since 1.1.0 */ public static class ProxyAdapter implements ProxyListener { /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyListener#proxyNotResolved(org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyEvent) */ public void proxyNotResolved(ProxyEvent event) { } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyListener#proxyResolved(org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyEvent) */ public void proxyResolved(ProxyEvent event) { } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyListener#proxyVoid(org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyEvent) */ public void proxyVoid(ProxyEvent event) { } } final private int proxyID; final private int proxyType; private ListenerList listenerList; private Expression expression; /** * Create with the given proxy id. * @param proxyid * * @since 1.1.0 */ public ExpressionProxy(int proxyid, int proxyType, Expression expression) { this.proxyID = proxyid; this.proxyType = proxyType; this.expression = expression; } /** * Get the expression this proxy is for. * @return * * @since 1.1.0 */ public Expression getExpression() { return expression; } /** * Used internally in expression to get the proxy type. * @return * * @since 1.1.0 */ protected final int getProxyType() { return proxyType; } /** * Return the proxy id. * @return * * @since 1.1.0 */ public final int getProxyID() { return proxyID; } /** * Add a listener. If listener already added, it has no effect. * @param listener * * @since 1.1.0 */ public void addProxyListener(ProxyListener listener) { if (listenerList == null) listenerList = new ListenerList(); listenerList.add(listener); } /** * Remove a listener. If listener not already added, then no error. * @param listener * * @since 1.1.0 */ public void removeProxyListener(ProxyListener listener) { if (listenerList != null) listenerList.remove(listener); } /** * Used by internal subclasses or Expression to know if anyone is listening. * @return * * @since 1.1.0 */ protected final boolean hasListeners() { return listenerList != null && !listenerList.isEmpty(); } /** * The proxy has been fired (one of the events has occurred). Subclasses should clean * up and not hold onto anything that would be expensive in case the proxy is still * held onto be someone. For example the default clears the listener list. * <p> * <b>Note:</b> Subclasses must call super.dispose(). * * @since 1.1.0 */ protected void dispose() { listenerList = null; expression = null; } /** * Used by internal subclasses or by Expression to fire the resolved event. Once fired all listeners are removed. * This is because only one kind of firing can be done for a expression proxy and then the proxy is dead. This * prevents listeners from being held on to if any one accidently still holds the proxy. * @param proxy * * @since 1.1.0 */ protected void fireResolved(IBeanProxy proxy) { if (hasListeners()) { ProxyEvent event = new ProxyEvent(this, proxy); Object[] listeners = listenerList.getListeners(); for (int i = 0; i < listeners.length; i++) { try { ((ProxyListener) listeners[i]).proxyResolved(event); } catch (RuntimeException e) { ProxyPlugin.getPlugin().getLogger().log(e, Level.WARNING); } } } dispose(); } /** * Used by internal subclasses or by Expression to fire the not resolved event. Once fired all listeners are removed. * This is because only one kind of firing can be done for a expression proxy and then the proxy is dead. This * prevents listeners from being held on to if any one accidently still holds the proxy. * * @since 1.1.0 */ protected void fireNotResolved() { if (hasListeners()) { ProxyEvent event = new ProxyEvent(this); Object[] listeners = listenerList.getListeners(); for (int i = 0; i < listeners.length; i++) { try { ((ProxyListener) listeners[i]).proxyNotResolved(event); } catch (RuntimeException e) { ProxyPlugin.getPlugin().getLogger().log(e, Level.WARNING); } } } dispose(); } /** * Used by internal subclasses or by Expression to fire the void resolved event. Once fired all listeners are removed. * This is because only one kind of firing can be done for a expression proxy and then the proxy is dead. This * prevents listeners from being held on to if any one accidently still holds the proxy. * * @since 1.1.0 */ protected void fireVoidResolved() { if (hasListeners()) { ProxyEvent event = new ProxyEvent(this); Object[] listeners = listenerList.getListeners(); for (int i = 0; i < listeners.length; i++) { try { ((ProxyListener) listeners[i]).proxyVoid(event); } catch (RuntimeException e) { ProxyPlugin.getPlugin().getLogger().log(e, Level.WARNING); } } } dispose(); } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.IProxy#isBeanProxy() */ public final boolean isBeanProxy() { return false; } /* (non-Javadoc) * @see org.eclipse.jem.internal.proxy.core.IProxy#isExpressionProxy() */ public final boolean isExpressionProxy() { return true; } /** * Is this proxy valid for reassignment. By default only if the type is NORMAL_EXPRESSION_PROXY. * Subclasses may override and return true in their cases. * * @return * * @since 1.1.0 */ public boolean isValidForReassignment() { return getProxyType() == Expression.NORMAL_EXPRESSION_PROXY; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return super.toString()+": "+getProxyID(); //$NON-NLS-1$ } }