001: /*
002: * Copyright 2003,2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package net.sf.cglib.reflect;
017:
018: import java.lang.reflect.*;
019: import java.util.*;
020: import net.sf.cglib.core.*;
021: import org.objectweb.asm.ClassVisitor;
022: import org.objectweb.asm.MethodVisitor;
023: import org.objectweb.asm.Type;
024:
025: abstract public class MulticastDelegate implements Cloneable {
026: protected Object[] targets = {};
027:
028: protected MulticastDelegate() {
029: }
030:
031: public List getTargets() {
032: return new ArrayList(Arrays.asList(targets));
033: }
034:
035: abstract public MulticastDelegate add(Object target);
036:
037: protected MulticastDelegate addHelper(Object target) {
038: MulticastDelegate copy = newInstance();
039: copy.targets = new Object[targets.length + 1];
040: System.arraycopy(targets, 0, copy.targets, 0, targets.length);
041: copy.targets[targets.length] = target;
042: return copy;
043: }
044:
045: public MulticastDelegate remove(Object target) {
046: for (int i = targets.length - 1; i >= 0; i--) {
047: if (targets[i].equals(target)) {
048: MulticastDelegate copy = newInstance();
049: copy.targets = new Object[targets.length - 1];
050: System.arraycopy(targets, 0, copy.targets, 0, i);
051: System.arraycopy(targets, i + 1, copy.targets, i,
052: targets.length - i - 1);
053: return copy;
054: }
055: }
056: return this ;
057: }
058:
059: abstract public MulticastDelegate newInstance();
060:
061: public static MulticastDelegate create(Class iface) {
062: Generator gen = new Generator();
063: gen.setInterface(iface);
064: return gen.create();
065: }
066:
067: public static class Generator extends AbstractClassGenerator {
068: private static final Source SOURCE = new Source(
069: MulticastDelegate.class.getName());
070: private static final Type MULTICAST_DELEGATE = TypeUtils
071: .parseType("net.sf.cglib.reflect.MulticastDelegate");
072: private static final Signature NEW_INSTANCE = new Signature(
073: "newInstance", MULTICAST_DELEGATE, new Type[0]);
074: private static final Signature ADD_DELEGATE = new Signature(
075: "add", MULTICAST_DELEGATE,
076: new Type[] { Constants.TYPE_OBJECT });
077: private static final Signature ADD_HELPER = new Signature(
078: "addHelper", MULTICAST_DELEGATE,
079: new Type[] { Constants.TYPE_OBJECT });
080:
081: private Class iface;
082:
083: public Generator() {
084: super (SOURCE);
085: }
086:
087: protected ClassLoader getDefaultClassLoader() {
088: return iface.getClassLoader();
089: }
090:
091: public void setInterface(Class iface) {
092: this .iface = iface;
093: }
094:
095: public MulticastDelegate create() {
096: setNamePrefix(MulticastDelegate.class.getName());
097: return (MulticastDelegate) super .create(iface.getName());
098: }
099:
100: public void generateClass(ClassVisitor cv) {
101: final MethodInfo method = ReflectUtils
102: .getMethodInfo(ReflectUtils
103: .findInterfaceMethod(iface));
104:
105: ClassEmitter ce = new ClassEmitter(cv);
106: ce.begin_class(Constants.V1_2, Constants.ACC_PUBLIC,
107: getClassName(), MULTICAST_DELEGATE,
108: new Type[] { Type.getType(iface) },
109: Constants.SOURCE_FILE);
110: EmitUtils.null_constructor(ce);
111:
112: // generate proxied method
113: emitProxy(ce, method);
114:
115: // newInstance
116: CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
117: NEW_INSTANCE, null);
118: e.new_instance_this ();
119: e.dup();
120: e.invoke_constructor_this ();
121: e.return_value();
122: e.end_method();
123:
124: // add
125: e = ce.begin_method(Constants.ACC_PUBLIC, ADD_DELEGATE,
126: null);
127: e.load_this ();
128: e.load_arg(0);
129: e.checkcast(Type.getType(iface));
130: e.invoke_virtual_this (ADD_HELPER);
131: e.return_value();
132: e.end_method();
133:
134: ce.end_class();
135: }
136:
137: private void emitProxy(ClassEmitter ce, final MethodInfo method) {
138: final CodeEmitter e = EmitUtils.begin_method(ce, method,
139: Constants.ACC_PUBLIC);
140: Type returnType = method.getSignature().getReturnType();
141: final boolean returns = returnType != Type.VOID_TYPE;
142: Local result = null;
143: if (returns) {
144: result = e.make_local(returnType);
145: e.zero_or_null(returnType);
146: e.store_local(result);
147: }
148: e.load_this ();
149: e.super _getfield("targets", Constants.TYPE_OBJECT_ARRAY);
150: final Local result2 = result;
151: EmitUtils.process_array(e, Constants.TYPE_OBJECT_ARRAY,
152: new ProcessArrayCallback() {
153: public void processElement(Type type) {
154: e.checkcast(Type.getType(iface));
155: e.load_args();
156: e.invoke(method);
157: if (returns) {
158: e.store_local(result2);
159: }
160: }
161: });
162: if (returns) {
163: e.load_local(result);
164: }
165: e.return_value();
166: e.end_method();
167: }
168:
169: protected Object firstInstance(Class type) {
170: // make a new instance in case first object is used with a long list of targets
171: return ((MulticastDelegate) ReflectUtils.newInstance(type))
172: .newInstance();
173: }
174:
175: protected Object nextInstance(Object instance) {
176: return ((MulticastDelegate) instance).newInstance();
177: }
178: }
179: }
|