PageRenderTime 39ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/net.bioclipse.core/src/net/bioclipse/managers/business/AbstractManagerMethodDispatcher.java

https://github.com/miquelrojascherto/bioclipse.core
Java | 343 lines | 292 code | 40 blank | 11 comment | 60 complexity | d838417f0d962ce0fda0206a907c0779 MD5 | raw file
Possible License(s): Apache-2.0
  1. package net.bioclipse.managers.business;
  2. import java.lang.reflect.InvocationTargetException;
  3. import java.lang.reflect.Method;
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.Collections;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import java.util.WeakHashMap;
  11. import net.bioclipse.core.IResourcePathTransformer;
  12. import net.bioclipse.core.ResourcePathTransformer;
  13. import net.bioclipse.core.business.BioclipseException;
  14. import net.bioclipse.jobs.BioclipseJob;
  15. import net.bioclipse.jobs.BioclipseJobUpdateHook;
  16. import net.bioclipse.jobs.BioclipseUIJob;
  17. import net.bioclipse.jobs.IReturner;
  18. import net.bioclipse.managers.MonitorContainer;
  19. import org.aopalliance.intercept.MethodInterceptor;
  20. import org.aopalliance.intercept.MethodInvocation;
  21. import org.apache.log4j.Logger;
  22. import org.eclipse.core.resources.IFile;
  23. import org.eclipse.core.runtime.IProgressMonitor;
  24. import org.eclipse.core.runtime.IStatus;
  25. import org.eclipse.core.runtime.NullProgressMonitor;
  26. import org.eclipse.core.runtime.Status;
  27. import org.eclipse.swt.widgets.Display;
  28. import org.eclipse.ui.progress.WorkbenchJob;
  29. /**
  30. * @author jonalv
  31. *
  32. */
  33. public abstract class AbstractManagerMethodDispatcher
  34. implements MethodInterceptor {
  35. protected IResourcePathTransformer transformer
  36. = ResourcePathTransformer.getInstance();
  37. private final Logger logger
  38. = Logger.getLogger( AbstractManagerMethodDispatcher.class );
  39. private Map<String, Long> lastWarningTimes
  40. = Collections.synchronizedMap( new HashMap<String, Long>() );
  41. protected static class ReturnCollector<T> implements IReturner<T> {
  42. private volatile T returnValue = null;
  43. private List<T> returnValues = new ArrayList<T>();
  44. public void partialReturn( T object ) {
  45. if ( returnValue != null ) {
  46. throw new IllegalStateException(
  47. "Method completeReturn already called. " +
  48. "Can't do more returns after completeReturn" );
  49. }
  50. synchronized ( returnValues ) {
  51. returnValues.add( object );
  52. }
  53. }
  54. public List<T> getReturnValues() {
  55. synchronized ( returnValues ) {
  56. return returnValues;
  57. }
  58. }
  59. public void completeReturn( T object ) {
  60. if ( !returnValues.isEmpty() ) {
  61. throw new IllegalStateException(
  62. "Partial returns detected. " +
  63. "Can't do a complete return after partial " +
  64. "returning commenced" );
  65. }
  66. returnValue = object;
  67. }
  68. public Object getReturnValue() {
  69. return returnValue;
  70. }
  71. }
  72. public Object invoke( MethodInvocation invocation ) throws Throwable {
  73. IBioclipseManager manager = (IBioclipseManager) invocation.getThis();
  74. Method m = findMethodToRun(invocation);
  75. if ( invocation.getMethod().getAnnotation( GuiAction.class ) != null ) {
  76. logger.debug( manager.getManagerName() + "."
  77. + invocation.getMethod().getName()
  78. + " has @GuiAction - running in gui thread" );
  79. return doInvokeInGuiThread( (IBioclipseManager)invocation.getThis(),
  80. m,
  81. invocation.getArguments(),
  82. invocation );
  83. }
  84. Object returnValue;
  85. if ( invocation.getMethod().getReturnType() != BioclipseJob.class &&
  86. invocation.getMethod().getReturnType() != void.class ) {
  87. if ( Arrays.asList( m.getParameterTypes() )
  88. .contains( IProgressMonitor.class) &&
  89. !(this instanceof JavaScriptManagerMethodDispatcher) ) {
  90. int timeout = 120;
  91. String warning = manager.getManagerName() + "."
  92. + invocation.getMethod().getName()
  93. + " is not void or returning a BioclipseJob."
  94. + " But implementation takes a progress "
  95. + "monitor. Can not run as Job. Running in "
  96. + "same thread. This message will not be "
  97. + "repeated withing the next " + timeout
  98. + "seconds";
  99. if ( !lastWarningTimes.containsKey( warning ) ||
  100. System.currentTimeMillis()
  101. - lastWarningTimes.get( warning ) > 1000 * timeout ) {
  102. lastWarningTimes.put( warning, System.currentTimeMillis() );
  103. logger.warn( warning );
  104. }
  105. }
  106. returnValue = doInvokeInSameThread( (IBioclipseManager)
  107. invocation.getThis(),
  108. m,
  109. invocation.getArguments(),
  110. invocation );
  111. }
  112. else {
  113. logger.debug( "Creating job for " + manager.getManagerName() + "."
  114. + invocation.getMethod().getName() );
  115. returnValue = doInvoke( (IBioclipseManager)invocation.getThis(),
  116. m,
  117. invocation.getArguments(),
  118. invocation );
  119. }
  120. if ( returnValue instanceof IFile &&
  121. invocation.getMethod().getReturnType() == String.class ) {
  122. returnValue = ( (IFile) returnValue ).getLocationURI()
  123. .getPath();
  124. }
  125. return returnValue;
  126. }
  127. private BioclipseUIJob<Object> getBioclipseUIJob(Object[] arguments) {
  128. for ( Object o : arguments ) {
  129. if ( o instanceof BioclipseUIJob) {
  130. return (BioclipseUIJob<Object>) o;
  131. }
  132. }
  133. return null;
  134. }
  135. protected abstract Object doInvokeInGuiThread(
  136. IBioclipseManager manager,
  137. Method m,
  138. Object[] arguments,
  139. MethodInvocation invocation );
  140. protected abstract Object doInvokeInSameThread(
  141. IBioclipseManager manager,
  142. Method m,
  143. Object[] arguments,
  144. MethodInvocation invocation )
  145. throws BioclipseException;
  146. public Object doInvoke( IBioclipseManager manager,
  147. Method method,
  148. Object[] arguments,
  149. MethodInvocation methodCalled )
  150. throws BioclipseException {
  151. List<Object> newArguments = new ArrayList<Object>();
  152. newArguments.addAll( Arrays.asList( arguments ) );
  153. boolean doingPartialReturns = false;
  154. ReturnCollector returnCollector = new ReturnCollector();
  155. //add partial returner
  156. for ( Class<?> param : method.getParameterTypes() ) {
  157. if ( param == IReturner.class ) {
  158. doingPartialReturns = true;
  159. newArguments.add( returnCollector );
  160. }
  161. }
  162. //remove any BioclipseUIJob
  163. BioclipseUIJob uiJob = null;
  164. for ( Object o : newArguments ) {
  165. if ( o instanceof BioclipseUIJob) {
  166. uiJob = (BioclipseUIJob) o;
  167. }
  168. }
  169. if ( uiJob != null ) {
  170. newArguments.remove( uiJob );
  171. }
  172. if ( Arrays.asList( method.getParameterTypes() )
  173. .contains( IProgressMonitor.class )
  174. ) {
  175. IProgressMonitor m = MonitorContainer.getInstance().getMonitor();
  176. if ( m == null ) {
  177. m = new NullProgressMonitor();
  178. }
  179. newArguments.add( m );
  180. }
  181. arguments = newArguments.toArray();
  182. //translate String -> IFile
  183. for ( int i = 0; i < arguments.length; i++ ) {
  184. if ( arguments[i] instanceof String &&
  185. method.getParameterTypes()[i] == IFile.class ) {
  186. arguments[i]
  187. = transformer.transform( (String)arguments[i] );
  188. }
  189. }
  190. Object returnValue = null;
  191. try {
  192. if ( doingPartialReturns ) {
  193. method.invoke( manager, arguments );
  194. returnValue = returnCollector.getReturnValue();
  195. if ( returnValue == null ) {
  196. returnValue = returnCollector.getReturnValues();
  197. }
  198. }
  199. else {
  200. returnValue = method.invoke( manager, arguments );
  201. }
  202. } catch ( IllegalArgumentException e ) {
  203. throw new RuntimeException("Failed to run method", e);
  204. } catch ( IllegalAccessException e ) {
  205. throw new RuntimeException("Failed to run method", e);
  206. } catch ( InvocationTargetException e ) {
  207. Throwable t = e.getCause();
  208. while ( t != null ) {
  209. if ( t instanceof BioclipseException ) {
  210. throw (BioclipseException)t;
  211. }
  212. t = t.getCause();
  213. }
  214. throw new RuntimeException("Failed to run method", e);
  215. }
  216. if ( uiJob != null ) {
  217. uiJob.setReturnValue( returnValue );
  218. final BioclipseUIJob finalUiJob = uiJob;
  219. new WorkbenchJob("Refresh") {
  220. @Override
  221. public IStatus runInUIThread(
  222. IProgressMonitor monitor ) {
  223. finalUiJob.runInUI();
  224. return Status.OK_STATUS;
  225. }
  226. }.schedule();
  227. }
  228. return returnValue;
  229. }
  230. private Method findMethodToRun(MethodInvocation invocation) {
  231. Method result;
  232. //If a method with the same signature exists use that one
  233. try {
  234. result = invocation.getThis().getClass()
  235. .getMethod( invocation.getMethod()
  236. .getName(),
  237. invocation.getMethod()
  238. .getParameterTypes() );
  239. }
  240. catch ( SecurityException e ) {
  241. throw new RuntimeException("Failed to find the method to run", e);
  242. }
  243. catch ( NoSuchMethodException e ) {
  244. result = null;
  245. }
  246. if ( result != null ) {
  247. return result;
  248. }
  249. //Look for "the JavaScript method" (taking String instead of IFile)
  250. METHODS:
  251. for ( Method m : invocation.getThis().getClass().getMethods() ) {
  252. Method refMethod = invocation.getMethod();
  253. int refLength = refMethod.getParameterTypes().length;
  254. int mLength = m.getParameterTypes().length;
  255. if ( m.getName().equals( refMethod.getName() ) &&
  256. mLength >= refLength &&
  257. mLength <= refLength + 2 ) {
  258. PARAMS:
  259. for ( int i = 0, j = 0;
  260. i < m.getParameterTypes().length;
  261. i++ ) {
  262. Class<?> currentParam = m.getParameterTypes()[i];
  263. if ( currentParam == IReturner.class ) {
  264. continue PARAMS;
  265. }
  266. if ( invocation.getMethod()
  267. .getParameterTypes().length >= j + 1 &&
  268. ( invocation.getMethod().getParameterTypes()[j]
  269. == BioclipseUIJob.class ||
  270. invocation.getMethod().getParameterTypes()[j]
  271. == BioclipseJobUpdateHook.class ) ) {
  272. j++;
  273. }
  274. if ( currentParam == IProgressMonitor.class &&
  275. // can only skip if there is nothing
  276. // corresponding in the refMethods parameter types.
  277. refMethod.getParameterTypes().length < j + 1 ) {
  278. continue PARAMS;
  279. }
  280. if ( invocation.getMethod()
  281. .getParameterTypes().length <= j ) {
  282. continue METHODS;
  283. }
  284. Class<?> refParam = invocation.getMethod()
  285. .getParameterTypes()[j++];
  286. if ( currentParam == refParam ) {
  287. continue PARAMS;
  288. }
  289. if ( currentParam == IFile.class &&
  290. refParam == String.class ) {
  291. continue PARAMS;
  292. }
  293. continue METHODS;
  294. }
  295. return m;
  296. }
  297. }
  298. throw new RuntimeException(
  299. "Failed to find a method to run on "
  300. + invocation.getThis().getClass() +
  301. " that could correspond to " + invocation.getMethod() );
  302. }
  303. }