OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
Executor.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Diagnostics; //for [DebuggerNonUserCode]
31 using System.Reflection;
32 using System.Runtime.Remoting.Lifetime;
33 using OpenSim.Region.ScriptEngine.Shared;
34 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
35 using log4net;
36 
37 namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
38 {
39  public class Executor
40  {
41  // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 
46  protected IScript m_Script;
47 
48  protected Dictionary<string, scriptEvents> m_eventFlagsMap = new Dictionary<string, scriptEvents>();
49 
50  [Flags]
51  public enum scriptEvents : int
52  {
53  None = 0,
54  attach = 1,
55  collision = 16,
56  collision_end = 32,
57  collision_start = 64,
58  control = 128,
59  dataserver = 256,
60  email = 512,
61  http_response = 1024,
62  land_collision = 2048,
63  land_collision_end = 4096,
64  land_collision_start = 8192,
65  at_target = 16384,
66  at_rot_target = 16777216,
67  listen = 32768,
68  money = 65536,
69  moving_end = 131072,
70  moving_start = 262144,
71  not_at_rot_target = 524288,
72  not_at_target = 1048576,
73  remote_data = 8388608,
74  run_time_permissions = 268435456,
75  state_entry = 1073741824,
76  state_exit = 2,
77  timer = 4,
78  touch = 8,
79  touch_end = 536870912,
80  touch_start = 2097152,
81  transaction_result = 33554432,
82  object_rez = 4194304
83  }
84 
85  // Cache functions by keeping a reference to them in a dictionary
86  private Dictionary<string, MethodInfo> Events = new Dictionary<string, MethodInfo>();
87  private Dictionary<string, scriptEvents> m_stateEvents = new Dictionary<string, scriptEvents>();
88 
89  public Executor(IScript script)
90  {
91  m_Script = script;
92  initEventFlags();
93  }
94 
95  public scriptEvents GetStateEventFlags(string state)
96  {
97  //m_log.Debug("Get event flags for " + state);
98 
99  // Check to see if we've already computed the flags for this state
100  scriptEvents eventFlags = scriptEvents.None;
101  if (m_stateEvents.ContainsKey(state))
102  {
103  m_stateEvents.TryGetValue(state, out eventFlags);
104  return eventFlags;
105  }
106 
107  Type type=m_Script.GetType();
108 
109  // Fill in the events for this state, cache the results in the map
110  foreach (KeyValuePair<string, scriptEvents> kvp in m_eventFlagsMap)
111  {
112  string evname = state + "_event_" + kvp.Key;
113  //m_log.Debug("Trying event "+evname);
114  try
115  {
116  MethodInfo mi = type.GetMethod(evname);
117  if (mi != null)
118  {
119  //m_log.Debug("Found handler for " + kvp.Key);
120  eventFlags |= kvp.Value;
121  }
122  }
123  catch(Exception)
124  {
125  //m_log.Debug("Exeption in GetMethod:\n"+e.ToString());
126  }
127  }
128 
129  // Save the flags we just computed and return the result
130  if (eventFlags != 0)
131  m_stateEvents.Add(state, eventFlags);
132 
133  //m_log.Debug("Returning {0:x}", eventFlags);
134  return (eventFlags);
135  }
136 
137  [DebuggerNonUserCode]
138  public void ExecuteEvent(string state, string FunctionName, object[] args)
139  {
140  // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
141  // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
142 
143  string EventName = state + "_event_" + FunctionName;
144 
145 //#if DEBUG
146  //m_log.Debug("ScriptEngine: Script event function name: " + EventName);
147 //#endif
148 
149  if (Events.ContainsKey(EventName) == false)
150  {
151  // Not found, create
152  Type type = m_Script.GetType();
153  try
154  {
155  MethodInfo mi = type.GetMethod(EventName);
156  Events.Add(EventName, mi);
157  }
158  catch
159  {
160  // m_log.Error("Event "+EventName+" not found.");
161  // Event name not found, cache it as not found
162  Events.Add(EventName, null);
163  }
164  }
165 
166  // Get event
167  MethodInfo ev = null;
168  Events.TryGetValue(EventName, out ev);
169 
170  if (ev == null) // No event by that name!
171  {
172  //m_log.Debug("ScriptEngine Can not find any event named: \String.Empty + EventName + "\String.Empty);
173  return;
174  }
175 
176 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
177 #if DEBUG
178  //m_log.Debug("ScriptEngine: Executing function name: " + EventName);
179 #endif
180  // Found
181  try
182  {
183  ev.Invoke(m_Script, args);
184  }
185  catch (TargetInvocationException tie)
186  {
187  // Grab the inner exception and rethrow it, unless the inner
188  // exception is an EventAbortException as this indicates event
189  // invocation termination due to a state change.
190  // DO NOT THROW JUST THE INNER EXCEPTION!
191  // FriendlyErrors depends on getting the whole exception!
192  //
193  if (!(tie.InnerException is EventAbortException))
194  {
195  throw;
196  }
197  }
198 
199  }
200 
201  protected void initEventFlags()
202  {
203  // Initialize the table if it hasn't already been done
204  if (m_eventFlagsMap.Count > 0)
205  {
206  return;
207  }
208 
209  m_eventFlagsMap.Add("attach", scriptEvents.attach);
210  m_eventFlagsMap.Add("at_rot_target", scriptEvents.at_rot_target);
211  m_eventFlagsMap.Add("at_target", scriptEvents.at_target);
212  // m_eventFlagsMap.Add("changed",(long)scriptEvents.changed);
213  m_eventFlagsMap.Add("collision", scriptEvents.collision);
214  m_eventFlagsMap.Add("collision_end", scriptEvents.collision_end);
215  m_eventFlagsMap.Add("collision_start", scriptEvents.collision_start);
216  m_eventFlagsMap.Add("control", scriptEvents.control);
217  m_eventFlagsMap.Add("dataserver", scriptEvents.dataserver);
218  m_eventFlagsMap.Add("email", scriptEvents.email);
219  m_eventFlagsMap.Add("http_response", scriptEvents.http_response);
220  m_eventFlagsMap.Add("land_collision", scriptEvents.land_collision);
221  m_eventFlagsMap.Add("land_collision_end", scriptEvents.land_collision_end);
222  m_eventFlagsMap.Add("land_collision_start", scriptEvents.land_collision_start);
223  // m_eventFlagsMap.Add("link_message",scriptEvents.link_message);
224  m_eventFlagsMap.Add("listen", scriptEvents.listen);
225  m_eventFlagsMap.Add("money", scriptEvents.money);
226  m_eventFlagsMap.Add("moving_end", scriptEvents.moving_end);
227  m_eventFlagsMap.Add("moving_start", scriptEvents.moving_start);
228  m_eventFlagsMap.Add("not_at_rot_target", scriptEvents.not_at_rot_target);
229  m_eventFlagsMap.Add("not_at_target", scriptEvents.not_at_target);
230  // m_eventFlagsMap.Add("no_sensor",(long)scriptEvents.no_sensor);
231  // m_eventFlagsMap.Add("on_rez",(long)scriptEvents.on_rez);
232  m_eventFlagsMap.Add("remote_data", scriptEvents.remote_data);
233  m_eventFlagsMap.Add("run_time_permissions", scriptEvents.run_time_permissions);
234  // m_eventFlagsMap.Add("sensor",(long)scriptEvents.sensor);
235  m_eventFlagsMap.Add("state_entry", scriptEvents.state_entry);
236  m_eventFlagsMap.Add("state_exit", scriptEvents.state_exit);
237  m_eventFlagsMap.Add("timer", scriptEvents.timer);
238  m_eventFlagsMap.Add("touch", scriptEvents.touch);
239  m_eventFlagsMap.Add("touch_end", scriptEvents.touch_end);
240  m_eventFlagsMap.Add("touch_start", scriptEvents.touch_start);
241  m_eventFlagsMap.Add("transaction_result", scriptEvents.transaction_result);
242  m_eventFlagsMap.Add("object_rez", scriptEvents.object_rez);
243  }
244  }
245 }
void ExecuteEvent(string state, string FunctionName, object[] args)
Definition: Executor.cs:138
IScript m_Script
Contains the script to execute functions in.
Definition: Executor.cs:46