001 /* 002 Copyright (C) 2002-2004 Renaud Pawlak <renaud@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public 015 License along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 017 USA */ 018 019 package org.objectweb.jac.aspects.gui; 020 021 import java.util.Arrays; 022 import java.util.Iterator; 023 import java.util.List; 024 import org.apache.log4j.Logger; 025 import org.objectweb.jac.core.Collaboration; 026 import org.objectweb.jac.core.rtti.AbstractMethodItem; 027 import org.objectweb.jac.core.rtti.ConstructorItem; 028 import org.objectweb.jac.core.rtti.MethodItem; 029 import org.objectweb.jac.util.Exceptions; 030 031 /** 032 * This class allows the programmer to invoke a given method in a new 033 * thread. 034 * 035 * <p>JAC programmers should use JAC to pass some attibutes of the 036 * current thread to the new thread. 037 * 038 * <p>Typical use: 039 * <ul><pre> 040 * InvokeThread.run( myObject, "myMethodName", 041 * new Object[] { arg0, ...}, 042 * new String[] { attrName0, ... }, 043 * new Object[] { attrValue0, ... }, 044 * new String[] { lattrName0, ... }, 045 * new Object[] { lattrValue0, ... } ); 046 * </pre></ul> */ 047 048 public class InvokeThread extends Thread { 049 static Logger logger = Logger.getLogger("gui.threads"); 050 static Logger loggerInput = Logger.getLogger("gui.input"); 051 052 InvokeEvent invoke; 053 Object returnValue; 054 String[] attrNames; 055 Object[] attrValues; 056 String[] lattrNames; 057 Object[] lattrValues; 058 Collaboration parentCollaboration; 059 boolean showResult = true; 060 061 /** 062 * Runs a method in a new thread and sets a display for this 063 * thread. 064 * 065 * @param object the object that contains the method to call 066 * @param method the method to call 067 * @param parameters the parameters to pass to the method 068 * @param attrNames the attribute names to set into the new thread 069 * collaboration 070 * @param attrValues the values of these attributes 071 * @param lattrNames the local attribute names to set into the new 072 * thread collaboration 073 * @param lattrValues the values of these local attributes */ 074 075 076 public static InvokeThread run(InvokeEvent invoke, 077 String[] attrNames, Object[] attrValues, 078 String[] lattrNames, Object[] lattrValues) { 079 InvokeThread ret = new InvokeThread(invoke); 080 ret.parentCollaboration = Collaboration.get(); 081 ret.attrNames = attrNames; 082 ret.attrValues = attrValues; 083 ret.lattrNames = lattrNames; 084 ret.lattrValues = lattrValues; 085 ret.start(); 086 return ret; 087 } 088 089 /** 090 * Runs a method in a new thread and sets a display for this 091 * thread. Do not show any results on the display. 092 * 093 * @param object the object that contains the method to call 094 * @param method the method to call 095 * @param parameters the parameters to pass to the method 096 * @param attrNames the attribute names to set into the new thread 097 * collaboration 098 * @param attrValues the values of these attributes 099 * @param lattrNames the local attribute names to set into the new 100 * thread collaboration 101 * @param lattrValues the values of these local attributes */ 102 103 public static 104 InvokeThread quietRun(InvokeEvent invoke, 105 String[] attrNames, Object[] attrValues, 106 String[] lattrNames, Object[] lattrValues) 107 { 108 InvokeThread ret = new InvokeThread(invoke); 109 ret.parentCollaboration = Collaboration.get(); 110 ret.attrNames = attrNames; 111 ret.attrValues = attrValues; 112 ret.lattrNames = lattrNames; 113 ret.lattrValues = lattrValues; 114 // ret.showResult = false; 115 ret.start(); 116 return ret; 117 } 118 119 /** 120 * Runs a method in a new thread. 121 * 122 * @param object the object that contains the method to call 123 * @param method the method to call 124 * @param parameters the parameters to pass to the method */ 125 126 public static InvokeThread run(InvokeEvent invoke) { 127 InvokeThread ret = new InvokeThread(invoke); 128 ret.start(); 129 return ret; 130 } 131 132 /** 133 * Creates a new thread that will invoke a method when started. 134 * 135 * <p>The programmer should use the static <code>run</code> 136 * methods. 137 * 138 * @param object the object that contains the method to invoke 139 * @param method the method to invoke when started 140 * @param parameters the parameters to pass to the method */ 141 142 public InvokeThread(InvokeEvent invoke) { 143 this.invoke = invoke; 144 } 145 146 147 public InvokeThread(InvokeEvent invoke, 148 String[] attrNames, Object[] attrValues, 149 String[] lattrNames, Object[] lattrValues) { 150 this.invoke = invoke; 151 this.parentCollaboration = Collaboration.get(); 152 this.attrNames = attrNames; 153 this.attrValues = attrValues; 154 this.lattrNames = lattrNames; 155 this.lattrValues = lattrValues; 156 this.showResult = false; 157 } 158 159 /** 160 * Runs the thread (and invoke the method that was given to the 161 * constructor with the right display in the collaboration). 162 * 163 * <p>Do not call this method directly. 164 */ 165 public void run() { 166 Collaboration collab = Collaboration.get(); 167 Object[] parameters = invoke.getParameters(); 168 AbstractMethodItem method = invoke.getMethod(); 169 Object substance = invoke.getSubstance(); 170 171 logger.debug("invokeThread "+this+": "+invoke); 172 if (parentCollaboration!=null) { 173 Iterator it = parentCollaboration.attributeNames().iterator(); 174 while (it.hasNext()) { 175 String attrName = (String)it.next(); 176 collab.addAttribute( 177 attrName,parentCollaboration.getAttribute(attrName)); 178 } 179 logger.debug("application = "+parentCollaboration.getCurApp()); 180 collab.setCurApp(parentCollaboration.getCurApp()); 181 } 182 if (attrNames != null) { 183 for (int i=0; i<attrNames.length; i++) { 184 logger.debug("setting attribute " + attrNames[i] + 185 " to " + attrValues[i]); 186 collab.addAttribute( 187 attrNames[i], attrValues[i]); 188 } 189 } 190 if (lattrNames != null) { 191 for (int i=0; i<lattrNames.length; i++) { 192 logger.debug("setting local attribute " + 193 lattrNames[i] + " to " + lattrValues[i]); 194 collab.addAttribute( 195 lattrNames[i], lattrValues[i]); 196 } 197 } 198 DisplayContext context = (DisplayContext)collab 199 .getAttribute(GuiAC.DISPLAY_CONTEXT); 200 201 CustomizedDisplay display = context.getDisplay(); 202 try { 203 logger.debug("InvokeThread " + invoke); 204 205 Class[] paramTypes = method.getParameterTypes(); 206 if (paramTypes.length != invoke.getParameters().length) 207 throw new RuntimeException("Wrong number of parameters ("+ 208 parameters.length+") for "+method); 209 for (int i=0; i<parameters.length; i++) { 210 if (parameters[i]==null) { 211 if (paramTypes[i] == float.class) { 212 method.setParameter(parameters,i,new Float(0.0)); 213 } else if (paramTypes[i] == long.class) { 214 method.setParameter(parameters,i,new Long(0)); 215 } else if (paramTypes[i] == double.class) { 216 method.setParameter(parameters,i,new Double(0.0)); 217 } else if (paramTypes[i] == byte.class) { 218 method.setParameter(parameters,i,new Byte((byte)0)); 219 } else if (paramTypes[i] == char.class) { 220 method.setParameter(parameters,i,new Character(' ')); 221 } else if (paramTypes[i] == short.class) { 222 method.setParameter(parameters,i,new Short((short)0)); 223 } else if (paramTypes[i] == int.class) { 224 method.setParameter(parameters,i,new Integer(0)); 225 } else if (paramTypes[i] == boolean.class) { 226 method.setParameter(parameters,i,Boolean.FALSE); 227 } 228 } 229 } 230 231 if (method instanceof ConstructorItem) { 232 returnValue = ((ConstructorItem)method).newInstance(parameters); 233 } else { 234 returnValue = ((MethodItem)method).invoke(substance, parameters); 235 } 236 237 if (display != null) { 238 display.onInvocationReturn(substance,method); 239 } 240 List hooks = (List)method.getAttribute(GuiAC.POST_INVOKE_HOOKS); 241 if (hooks!=null) { 242 Iterator i = hooks.iterator(); 243 while (i.hasNext()) { 244 AbstractMethodItem hook = (AbstractMethodItem)i.next(); 245 try { 246 loggerInput.debug("Invoking post hook "+hook.getName()); 247 hook.invoke( 248 null, 249 new Object[] {invoke}); 250 } catch (Exception e) { 251 loggerInput.error("Post invoke hook for "+ 252 substance+"."+ 253 method.getFullName()+" failed",e); 254 } 255 } 256 } 257 258 if (method.getType() != void.class) { 259 if (display != null && showResult) { 260 261 if (collab.getAttribute(GuiAC.OPEN_VIEW)!=null) { 262 display.openView(returnValue); 263 } else { 264 if(method.getAttribute(GuiAC.SMALL_TARGET_CONTAINER)!=null) { 265 EventHandler.get().onSelection(context,method,returnValue,null,null,false); 266 } else if (returnValue instanceof HandlerResult) { 267 EventHandler.get().handleResult(context,(HandlerResult)returnValue); 268 } else { 269 display.show(returnValue); 270 } 271 } 272 } 273 } else { 274 if (display != null && showResult) 275 display.refresh(); 276 } 277 } catch (Exception e) { 278 Throwable te = Exceptions.getTargetException(e); 279 logger.debug(this+" TargetException is "+te); 280 if (te instanceof TimeoutException) { 281 logger.debug(this+" Timeout"); 282 DialogView dialog = ((TimeoutException)te).getDialog(); 283 display.closeWindow(dialog,false); 284 display.addTimedoutDialog(dialog); 285 } else if (display != null && showResult) { 286 if (!(te instanceof org.objectweb.jac.util.VoidException)) 287 display.showModal(te,"Error","",context.getWindow(),false,false,true); 288 else 289 display.refresh(); 290 } 291 } 292 logger.debug("invokeThread done "+this+": "+ 293 substance+"."+method+Arrays.asList(parameters)); 294 } 295 296 Object getReturnValue() { 297 return returnValue; 298 } 299 } 300 301 class NotAvailableException extends Exception {}