2 * Copyright (c) 2003-2005 The BISON Project
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 package peersim.dynamics;
21 import peersim.graph.*;
22 import peersim.core.*;
23 import peersim.config.*;
24 import java.lang.reflect.*;
25 import java.util.ArrayList;
28 * Takes a {@link Linkable} protocol and adds connections using an arbitrary
30 * No connections are removed.
31 * The connections are added by an arbitrary method that can be specified
32 * in the configuration.
33 * The properties the method has to fulfill are the following
35 <li>It MUST be static</li>
36 <li>It MUST have a first argument that can be assigned from a class
37 that implements {@link Graph}.</li>
38 <li>It MAY contain zero or more arguments following the first one.</li>
39 <li>All the arguments after the first one MUST be of primitive type int,
40 long or double, except
41 the last one, which MAY be of type that can be assigned from
42 <code>java.util.Random</code></li>
44 The arguments are initialized using the configuration as follows.
46 <li>The first argument is the {@link Graph} that is passed to
48 <li>The arguments after the first one (indexed as 1,2,etc) are initialized
49 from configuration parameters of the form {@value #PAR_ARG}i, where i is the
51 <li>If the last argument can be assigned from
52 <code>java.util.Random</code> then it is initialized with
53 {@link CommonState#r}, the central source of randomness for the
56 For example, the class {@link WireWS} can be emulated by configuring
59 init.0.class GraphFactory
65 Note that the {@value #PAR_CLASS} parameter defaults to {@link GraphFactory},
66 and {@value #PAR_METHOD} defaults to "wire".
68 public class WireByMethod extends WireGraph {
70 //--------------------------------------------------------------------------
72 //--------------------------------------------------------------------------
75 * The prefix for the configuration properties that describe parameters.
78 private static final String PAR_ARG = "arg";
81 * The class that has the method we want to use. Defaults to
82 * {@link GraphFactory}.
85 private static final String PAR_CLASS = "class";
88 * The name of the method for wiring the graph. Defaults to <code>wire</code>.
91 private static final String PAR_METHOD = "method";
93 //--------------------------------------------------------------------------
95 //--------------------------------------------------------------------------
97 private final Object[] args;
99 private final Method method;
101 //--------------------------------------------------------------------------
103 //--------------------------------------------------------------------------
106 * Loads configuration. It verifies the constraints defined
107 * in {@link WireByMethod}.
108 * @param prefix the configuration prefix for this class
110 public WireByMethod(String prefix)
118 Configuration.getClass(prefix + "." + PAR_CLASS,
119 Class.forName("peersim.graph.GraphFactory"));
120 method = WireByMethod.getMethod(
122 Configuration.getString(prefix+"."+PAR_METHOD,"wire"));
126 throw new RuntimeException(e);
129 // set the constant args (those other than 0th)
130 Class[] argt = method.getParameterTypes();
131 args = new Object[argt.length];
132 for(int i=1; i<args.length; ++i)
135 if( argt[i]==int.class )
136 args[i]=Configuration.getInt(prefix+"."+PAR_ARG+i);
137 else if( argt[i]==long.class )
138 args[i]=Configuration.getLong(prefix+"."+PAR_ARG+i);
139 else if( argt[i]==double.class )
140 args[i]=Configuration.getDouble(prefix+"."+PAR_ARG+i);
141 else if(i==args.length-1 && argt[i].isInstance(CommonState.r))
142 args[i]=CommonState.r;
145 // we should neve get here
146 throw new RuntimeException("Unexpected error, please "+
147 "report this problem to the peersim team");
152 //--------------------------------------------------------------------------
155 * Search a wiring method in the specified class.
157 * the class where to find the method
159 * the method to be searched
160 * @return the requested method, if it fully conforms to the definition of
161 * the wiring methods.
163 private static Method getMethod(Class cl, String methodName)
164 throws NoSuchMethodException, ClassNotFoundException {
167 Method[] methods = cl.getMethods();
168 ArrayList<Method> list = new ArrayList<Method>();
169 for (Method m: methods) {
170 if (m.getName().equals(methodName)) {
175 if (list.size() == 0) {
176 throw new NoSuchMethodException("No method "
177 + methodName + " in class " + cl.getSimpleName());
178 } else if (list.size() > 1) {
179 throw new NoSuchMethodException("Multiple methods called "
180 + methodName + " in class " + cl.getSimpleName());
183 // Found a single method with the right name; check if
185 final Class graphClass = Class.forName("peersim.graph.Graph");
186 final Class randomClass = Class.forName("java.util.Random");
187 Method method = list.get(0);
188 Class[] pars = method.getParameterTypes();
189 if( pars.length < 1 || !pars[0].isAssignableFrom(graphClass) )
190 throw new NoSuchMethodException(method.getName() + " of class "
191 + cl.getSimpleName() + " is not a valid graph wiring method,"+
192 " it has to have peersim.graph.Graph as first argument type");
193 for(int i=1; i<pars.length; ++i)
194 if( !( pars[i]==int.class || pars[i]==long.class ||
195 pars[i]==double.class ||
196 (i==pars.length-1 && pars[i].isAssignableFrom(randomClass)) ) )
197 throw new NoSuchMethodException(method.getName() +
198 " of class "+ cl.getSimpleName()
199 + " is not a valid graph wiring method");
201 if(method.toString().indexOf("static")<0)
202 throw new NoSuchMethodException(method.getName() +
203 " of class "+ cl.getSimpleName()
204 + " is not a valid graph wiring method; it is not static");
210 //--------------------------------------------------------------------------
212 //--------------------------------------------------------------------------
214 /** Invokes the method passing g to it.*/
215 public void wire(Graph g) {
218 try { method.invoke(null,args); }
219 catch( Exception e ) { throw new RuntimeException(e); }