View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.uruma.binding.method;
17  
18  import java.lang.reflect.Method;
19  
20  import org.eclipse.core.runtime.IProgressMonitor;
21  import org.eclipse.core.runtime.IStatus;
22  import org.eclipse.core.runtime.Status;
23  import org.eclipse.core.runtime.jobs.Job;
24  import org.eclipse.swt.widgets.Display;
25  import org.seasar.framework.beans.BeanDesc;
26  import org.seasar.framework.beans.PropertyDesc;
27  import org.seasar.framework.beans.factory.BeanDescFactory;
28  import org.seasar.framework.util.MethodUtil;
29  import org.seasar.uruma.core.UrumaConstants;
30  import org.seasar.uruma.core.UrumaMessageCodes;
31  import org.seasar.uruma.desc.PartActionDesc;
32  import org.seasar.uruma.desc.PartActionDescFactory;
33  import org.seasar.uruma.jobs.ProgressMonitor;
34  import org.seasar.uruma.jobs.impl.RcpProgressMonitor;
35  import org.seasar.uruma.log.UrumaLogger;
36  
37  /**
38   * メソッドを非同期に実行するための {@link MethodBinding} です。<br />
39   * 本メソッドでは、実行対象オブジェクトに {@link ProgressMonitor} 型のプロパティが存在する場合、
40   * {@link ProgressMonitor} オブジェクトをインジェクションします。<br />
41   * また、{@link Display#getCurrent()} によって {@link Display} オブジェクトが取得できる場合には、
42   * {@link MethodCallback#callback(MethodBinding, Object[], Object)} メソッドの呼び出しを
43   * UI スレッド側で実行します。
44   * 
45   * @author y-komori
46   */
47  public class AsyncMethodBinding extends MethodBinding implements
48          UrumaMessageCodes {
49      private static final UrumaLogger logger = UrumaLogger
50              .getLogger(AsyncMethodBinding.class);
51  
52      private String taskNameProperty;
53  
54      private boolean cancelable;
55  
56      /**
57       * {@link AsyncMethodBinding} を構築します。<br />
58       * 
59       * @param target
60       *            ターゲットオブジェクト
61       * @param method
62       *            ターゲットメソッド
63       * @param callback
64       *            コールバックオブジェクト
65       */
66      AsyncMethodBinding(final Object target, final Method method,
67              final MethodCallback callback) {
68          super(target, method, callback);
69      }
70  
71      /*
72       * @see org.seasar.uruma.binding.method.MethodBinding#invoke(java.lang.Object[])
73       */
74      @Override
75      public Object invoke(final Object[] args) {
76          Object[] filteredArgs = args;
77          for (ArgumentsFilter filter : argumentsFilterList) {
78              filteredArgs = filter.filter(filteredArgs);
79          }
80  
81          String taskName = getTaskName(taskNameProperty, target);
82          AsyncJob job = new AsyncJob(taskName, this, filteredArgs, Display
83                  .getCurrent());
84          if (cancelable) {
85              job.setUser(true);
86          }
87          job.schedule();
88  
89          if (logger.isInfoEnabled()) {
90              logger.log(ASYNC_METHOD_SCHEDULED, UrumaLogger
91                      .getObjectDescription(target), method.getName(), args);
92          }
93  
94          return null;
95      }
96  
97      /**
98       * タスク名称を保持するプロパティ名を設定します。<br />
99       * 
100      * @param taskNameProperty
101      *            プロパティ名
102      */
103     public void setTaskNameProperty(final String taskNameProperty) {
104         this.taskNameProperty = taskNameProperty;
105     }
106 
107     /**
108      * キャンセル可能かどうかを設定します。<br />
109      * 
110      * @param cancelable
111      *            キャンセル可能な場合は <code>true</code>。
112      */
113     public void setCancelable(final boolean cancelable) {
114         this.cancelable = cancelable;
115     }
116 
117     protected String getTaskName(final String propName, final Object target) {
118         if (propName == null) {
119             return UrumaConstants.NULL_STRING;
120         }
121 
122         BeanDesc desc = BeanDescFactory.getBeanDesc(target.getClass());
123         if (desc.hasPropertyDesc(propName)) {
124             PropertyDesc pd = desc.getPropertyDesc(propName);
125             if (pd.isReadable()
126                     && String.class.isAssignableFrom(pd.getPropertyType())) {
127                 return (String) pd.getValue(target);
128             }
129         }
130         return UrumaConstants.NULL_STRING;
131     }
132 
133     protected void injectProgressMonitor(final Object target,
134             final IProgressMonitor monitor) {
135         PartActionDesc desc = PartActionDescFactory.getPartActionDesc(target
136                 .getClass());
137 
138         ProgressMonitor uMonitor = new RcpProgressMonitor(monitor);
139         desc.injectProgressMonitor(target, uMonitor);
140     }
141 
142     /**
143      * アクションを非同期実行するための {@link Job} です。<br />
144      * 
145      * @author y-komori
146      */
147     class AsyncJob extends Job {
148         private MethodBinding binding;
149 
150         private Object[] args;
151 
152         private Object returnValue;
153 
154         private Display display;
155 
156         /**
157          * {@link AsyncJob} を構築します。<br />
158          */
159         AsyncJob(final String name, final MethodBinding binding,
160                 final Object[] args, final Display display) {
161             super(name);
162             this.binding = binding;
163             this.args = args;
164             this.display = display;
165         }
166 
167         /*
168          * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
169          */
170         @Override
171         protected IStatus run(final IProgressMonitor monitor) {
172             if (logger.isInfoEnabled()) {
173                 logger.log(ASYNC_METHOD_START, UrumaLogger
174                         .getObjectDescription(target), method.getName(), args);
175             }
176 
177             try {
178                 injectProgressMonitor(target, monitor);
179                 returnValue = MethodUtil.invoke(binding.getMethod(), binding
180                         .getTarget(), args);
181 
182                 if (callback != null) {
183                     if (display != null) {
184                         display.asyncExec(new Runnable() {
185                             public void run() {
186                                 returnValue = callback.callback(binding, args,
187                                         returnValue);
188                             }
189                         });
190                     } else {
191                         returnValue = callback.callback(binding, args,
192                                 returnValue);
193                     }
194                 }
195             } catch (Throwable ex) {
196                 logger.log(EXCEPTION_OCCURED_INVOKING_METHOD, ex, binding
197                         .toString());
198             } finally {
199                 if (logger.isInfoEnabled()) {
200                     String desc = UrumaLogger.getObjectDescription(target);
201                     if (!monitor.isCanceled()) {
202                         logger.log(ASYNC_METHOD_END, desc, method.getName(),
203                                 returnValue);
204                     } else {
205                         logger.log(ASYNC_METHOD_CANCELED, desc, method
206                                 .getName(), returnValue);
207                     }
208                 }
209             }
210 
211             if (!monitor.isCanceled()) {
212                 return Status.OK_STATUS;
213             } else {
214                 return Status.CANCEL_STATUS;
215             }
216         }
217     }
218 }