/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package net.sf.cglib;

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

abstract public class MulticastDelegate implements Cloneable {
    /* package */ static final Class TYPE = MulticastDelegate.class;
    private static final FactoryCache cache = new FactoryCache();
    private static final ClassLoader defaultLoader = TYPE.getClassLoader();
    private static final ClassNameFactory nameFactory = new ClassNameFactory("MulticastByCGLIB");

    private static final MulticastDelegateKey keyFactory =
      (MulticastDelegateKey)KeyFactory.create(MulticastDelegateKey.class, null);

    private static final Method NEW_INSTANCE =
      ReflectUtils.findMethod("MulticastDelegate.cglib_newInstance()");

    // should be package-protected but causes problems on jdk1.2
    public interface MulticastDelegateKey {
        public Object newInstance(Class iface);
    }

    protected Object[] delegates = {};

    protected MulticastDelegate() {
    }

    public List getInvocationList() {
        return new ArrayList(Arrays.asList(delegates));
    }

    public MulticastDelegate add(Object delegate) {
        MulticastDelegate copy = cglib_newInstance();
        copy.delegates = new Object[delegates.length + 1];
        System.arraycopy(delegates, 0, copy.delegates, 0, delegates.length);
        copy.delegates[delegates.length] = delegate;
        return copy;
    }

    public MulticastDelegate remove(Object delegate) {
        for (int i = delegates.length - 1; i >= 0; i--) { 
            if (delegates[i].equals(delegate)) {
                MulticastDelegate copy = cglib_newInstance();
                copy.delegates = new Object[delegates.length - 1];
                System.arraycopy(delegates, 0, copy.delegates, 0, i);
                System.arraycopy(delegates, i + 1, copy.delegates, i, delegates.length - i - 1);
                return copy;
            }
        }
        return this;
    }

    abstract protected MulticastDelegate cglib_newInstance();

    public static MulticastDelegate create(Class iface) {
        return create(iface, null);
    }

    public static MulticastDelegate create(Class iface, ClassLoader loader) {
        if (loader == null) {
            loader = defaultLoader;
        }
        Object key = keyFactory.newInstance(iface);
        MulticastDelegate factory;
        synchronized (cache) {
            factory = (MulticastDelegate)cache.get(loader, key);
            if (factory == null) {
                String className = nameFactory.getNextName(iface);
                Method method = MethodDelegate.findInterfaceMethod(iface);
                Class result = new Generator(className, method, iface, loader).define();
                factory = (MulticastDelegate)ReflectUtils.newInstance(result, Constants.TYPES_EMPTY, null);
                cache.put(loader, key, factory);
            }
        }
        return factory.cglib_newInstance();
    }

    private static class Generator extends CodeGenerator {
        private Method method;
        private Class iface;

        public Generator(String className, Method method, Class iface, ClassLoader loader) {
            super(className, MulticastDelegate.class, loader);
            this.method = method;
            this.iface = iface;
        }

        protected void generate() throws NoSuchMethodException, NoSuchFieldException {
            declare_interface(iface);
            generateNullConstructor();

            // generate proxied method
            begin_method(method);
            Class returnType = method.getReturnType();
            final boolean returns = returnType != Void.TYPE;
            if (returns) {
                local_type("result", returnType);
                zero_or_null(returnType);
                store_local("result");
            }
            load_this();
            super_getfield("delegates");
            process_array(Object[].class, new ProcessArrayCallback() {
                    public void processElement(Class type) {
                        checkcast(iface);
                        load_args();
                        invoke(method);
                        if (returns) {
                            store_local("result");
                        }
                    }
                });
            if (returns) {
                load_local("result");
            }
            return_value();
            end_method();

            // newInstance
            begin_method(NEW_INSTANCE);
            new_instance_this();
            dup();
            invoke_constructor_this();
            return_value();
            end_method();
        }
    }
}

@@ -2736,77 +2736,8 @@
 e %7B%0A
-    /* package */ static final Class TYPE = MulticastDelegate.class;%0A
     
@@ -2851,20 +2851,39 @@
 oader = 
-TYPE
+MulticastDelegate.class
 .getClas
@@ -3251,16 +3251,239 @@
 nce()%22);
+%0A    private static final Method ADD =%0A      ReflectUtils.findMethod(%22MulticastDelegate.add(Object)%22);%0A    private static final Method ADD_HELPER =%0A      ReflectUtils.findMethod(%22MulticastDelegate.cglib_addHelper(Object)%22);
 %0A%0A    //
@@ -3820,32 +3820,41 @@
 s));%0A    %7D%0A%0A    
+abstract 
 public Multicast
@@ -3874,32 +3874,99 @@
 Object delegate)
+;%0A%0A    protected MulticastDelegate cglib_addHelper(Object delegate)
  %7B%0A        Multi
@@ -7461,16 +7461,233 @@
 ethod();
+%0A%0A            // add%0A            begin_method(ADD);%0A            load_this();%0A            load_arg(0);%0A            checkcast(iface);%0A            invoke(ADD_HELPER);%0A            return_value();%0A            end_method();
 %0A       

Make sure added object is correct class.