1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 //_______________________________________________
25 // imports
26 import com.sun.star.uno.XComponentContext;
27 import com.sun.star.lib.uno.helper.Factory;
28 import com.sun.star.lib.uno.helper.WeakBase;
29 import com.sun.star.lang.XServiceInfo;
30 import com.sun.star.awt.*;
31 import com.sun.star.beans.*;
32 import com.sun.star.task.*;
33 import com.sun.star.uno.*;
34 import java.lang.*;
35 import javax.swing.*;
36 
37 //_______________________________________________
38 // implementation
39 
40 /** it implements a simple job component.
41  *
42  *  Such jobs are executable in different ways:
43  *  <ul>
44  *      <li>registered for a special URL schema "vnd.sun.star.jobs:*" and used from the generic dispatch framework</li>
45  *      <li>the global com.sun.star.task.JobExecutor service and registered for special events.</li>
46  *  </ul>
47  */
48 public class AsyncJob extends    WeakBase implements XServiceInfo, XAsyncJob
49 {
50     //___________________________________________
51     // const
52     public final XComponentContext m_xCmpCtx;
53 
54     /** the const list of supported uno service names. */
55     public static final java.lang.String[] SERVICENAMES = {"com.sun.star.task.AsyncJob"};
56 
57     /** the const uno implementation name.
58      *  It must be an unique value! The best naming schema seams to use
59      *  a registered domain in reverse order ...
60      */
61     public static final java.lang.String IMPLEMENTATIONNAME = "com.sun.star.comp.framework.java.services.AsyncJob";
62 
63     //___________________________________________
64     // interface
65 
66     /** initialize a new instance of this class with default values. */
67     public AsyncJob( XComponentContext xCompContext )
68     {
69         m_xCmpCtx = xCompContext;
70     }
71 
72     //___________________________________________
73 
74     /** starts execution of this job.
75      *
76      *  @param  lArgs
77      *          list which contains:
78      *          <ul>
79      *              <li>generic job configuration data</li>
80      *              <li>job specific configuration data</li>
81      *              <li>some environment informations</li>
82      *              <li>may optional arguments of a corresponding dispatch request</li>
83      *          </ul>
84      *
85      *  @params xListener
86      *          callback to the executor of this job, which control our life time
87      *
88      *  @throws com.sun.star.lang.IllegalArgumentException
89      *          if given argument list seams to be wrong
90      */
91     public synchronized void executeAsync(com.sun.star.beans.NamedValue[] lArgs    ,
92                                           com.sun.star.task.XJobListener  xListener)
93         throws com.sun.star.lang.IllegalArgumentException
94     {
95         // For asynchronous jobs a valid listener reference is guaranteed normaly ...
96         if (xListener == null)
97             throw new com.sun.star.lang.IllegalArgumentException("invalid listener");
98 
99         // extract all possible sub list of given argument list
100         com.sun.star.beans.NamedValue[] lGenericConfig = null;
101         com.sun.star.beans.NamedValue[] lJobConfig     = null;
102         com.sun.star.beans.NamedValue[] lEnvironment   = null;
103         com.sun.star.beans.NamedValue[] lDynamicData   = null;
104 
105         int c = lArgs.length;
106         for (int i=0; i<c; ++i)
107         {
108             if (lArgs[i].Name.equals("Config"))
109                 lGenericConfig = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
110             else
111             if (lArgs[i].Name.equals("JobConfig"))
112                 lJobConfig = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
113             else
114             if (lArgs[i].Name.equals("Environment"))
115                 lEnvironment = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
116             else
117             if (lArgs[i].Name.equals("DynamicData"))
118                 lDynamicData = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
119         }
120 
121         // Analyze the environment info. This sub list is the only guaranteed one!
122         if (lEnvironment == null)
123             throw new com.sun.star.lang.IllegalArgumentException("no environment");
124 
125         java.lang.String          sEnvType   = null;
126         java.lang.String          sEventName = null;
127         com.sun.star.frame.XFrame xFrame     = null;
128         c = lEnvironment.length;
129         for (int i=0; i<c; ++i)
130         {
131             if (lEnvironment[i].Name.equals("EnvType"))
132                 sEnvType = com.sun.star.uno.AnyConverter.toString(lEnvironment[i].Value);
133             else
134             if (lEnvironment[i].Name.equals("EventName"))
135                 sEventName = com.sun.star.uno.AnyConverter.toString(lEnvironment[i].Value);
136             else
137             if (lEnvironment[i].Name.equals("Frame"))
138                 xFrame = (com.sun.star.frame.XFrame)com.sun.star.uno.AnyConverter.toObject(
139                             new com.sun.star.uno.Type(com.sun.star.frame.XFrame.class),
140                             lEnvironment[i].Value);
141         }
142 
143         // Further the environment property "EnvType" is required as minimum.
144         if (
145             (sEnvType==null) ||
146             (
147              (!sEnvType.equals("EXECUTOR")) &&
148              (!sEnvType.equals("DISPATCH"))
149             )
150            )
151         {
152             java.lang.String sMessage = "\"" + sEnvType + "\" isn't a valid value for EnvType";
153             throw new com.sun.star.lang.IllegalArgumentException(sMessage);
154         }
155 
156         // Analyze the set of shared config data.
157         java.lang.String sAlias = null;
158         if (lGenericConfig!=null)
159         {
160             c = lGenericConfig.length;
161             for (int i=0; i<c; ++i)
162             {
163                 if (lGenericConfig[i].Name.equals("Alias"))
164                     sAlias = com.sun.star.uno.AnyConverter.toString(lGenericConfig[i].Value);
165             }
166         }
167 
168         // do your job ...
169         // Here we print out all found arguments.
170         java.lang.String sOut = formatOutArgs(lGenericConfig, lJobConfig, lEnvironment, lDynamicData);
171         if (xFrame != null)
172             showInfoModal(xFrame.getContainerWindow(), "Arguments of AsyncJob initialization ...", sOut);
173         else
174             showInfoNonModal("Arguments of AsyncJob initialization ...", sOut);
175 
176         // use return value to start different actions
177         // But look for the right environment. Some options make no sense inside the wrong env.
178         com.sun.star.beans.NamedValue aDeactivation   = null;
179         com.sun.star.beans.NamedValue aDispatchResult = null;
180         com.sun.star.beans.NamedValue aSaveRequest    = null;
181 
182         // SaveArguments will be made everytimes!
183         c = 1;
184 
185         if (lJobConfig==null)
186             lJobConfig = new com.sun.star.beans.NamedValue[1];
187         lJobConfig[0] = new com.sun.star.beans.NamedValue();
188         lJobConfig[0].Name  = "arg_1";
189         lJobConfig[0].Value = "val_1";
190 
191         aSaveRequest = new com.sun.star.beans.NamedValue();
192         aSaveRequest.Name  = "SaveArguments";
193         aSaveRequest.Value = lJobConfig;
194 
195         // Deactivation is useful inside EXECUTOR environment only
196         if (sEnvType.equals("EXECUTOR"))
197         {
198             ++c;
199             aDeactivation       = new com.sun.star.beans.NamedValue();
200             aDeactivation.Name  = "Deactivate";
201             aDeactivation.Value = java.lang.Boolean.TRUE;
202         }
203 
204         // Sending of result events is useful inside DISPATCH environment only
205         if (sEnvType.equals("DISPATCH"))
206         {
207             ++c;
208             aDispatchResult       = new com.sun.star.beans.NamedValue();
209             aDispatchResult.Name  = "SendDispatchResult";
210             aDispatchResult.Value = new com.sun.star.frame.DispatchResultEvent(this, com.sun.star.frame.DispatchResultState.SUCCESS, null);
211         }
212 
213         // pack it together for return
214         int i=0;
215         com.sun.star.beans.NamedValue[] lReturn = new com.sun.star.beans.NamedValue[c];
216         lReturn[i++] = aSaveRequest;
217         if (aDeactivation!=null)
218             lReturn[i++] = aDeactivation;
219         if (aDispatchResult!=null)
220             lReturn[i++] = aDispatchResult;
221 
222         xListener.jobFinished(this, lReturn);
223     }
224 
225     //___________________________________________
226 
227     /** show an info box with the UNO based toolkit.
228      *
229      *  It tries to use the container window of a may well know
230      *  office frame as parent. If such parent window could be located,
231      *  the info box can be shown in modal mode. If a parent is missing
232      *  (because this job is called inside an EXECUTOR environment, which
233      *  does not set any frame context here) the info box can't be created!
234      *  Because the toolkit needs parents for non top level windows ...
235      *  In that case the only way is to implement this info box
236      *  native or make it non modal using java dialogs inside it's own thread ...
237      *  (see showInfoNonModal() too)
238      *
239      *  @param  xParent
240      *          used as parent window of the shown info box.
241      *
242      *  @param  sTitle
243      *          is shown as title of the info box.
244      *
245      *  @param  sMessage
246      *          inclused the message body, which is shown as info.
247      */
248 
249     private void showInfoModal( com.sun.star.awt.XWindow xParent  ,
250                                 java.lang.String         sTitle   ,
251                                 java.lang.String         sMessage )
252     {
253         try
254         {
255             // get access to the office toolkit environment
256             com.sun.star.awt.XToolkit xKit = (com.sun.star.awt.XToolkit)UnoRuntime.queryInterface(
257                  com.sun.star.awt.XToolkit.class,
258                  m_xCmpCtx.getServiceManager().createInstanceWithContext("com.sun.star.awt.Toolkit",
259                                                                          m_xCmpCtx));
260 
261             // describe the info box ini it's parameters
262             com.sun.star.awt.WindowDescriptor aDescriptor = new com.sun.star.awt.WindowDescriptor();
263             aDescriptor.WindowServiceName = "infobox";
264             aDescriptor.Bounds            = new com.sun.star.awt.Rectangle(0,0,300,200);
265             aDescriptor.WindowAttributes  = com.sun.star.awt.WindowAttribute.BORDER   |
266                                             com.sun.star.awt.WindowAttribute.MOVEABLE |
267                                             com.sun.star.awt.WindowAttribute.CLOSEABLE;
268             aDescriptor.Type              = com.sun.star.awt.WindowClass.MODALTOP;
269             aDescriptor.ParentIndex       = 1;
270             aDescriptor.Parent            = (com.sun.star.awt.XWindowPeer)UnoRuntime.queryInterface(
271                                                 com.sun.star.awt.XWindowPeer.class,
272                                                 xParent);
273 
274             // create the info box window
275             com.sun.star.awt.XWindowPeer xPeer    = xKit.createWindow(aDescriptor);
276             com.sun.star.awt.XMessageBox xInfoBox = (com.sun.star.awt.XMessageBox)UnoRuntime.queryInterface(
277                                                         com.sun.star.awt.XMessageBox.class,
278                                                         xPeer);
279             if (xInfoBox == null)
280                 return;
281 
282             // fill it with all given informations and show it
283             xInfoBox.setCaptionText(sTitle);
284             xInfoBox.setMessageText(sMessage);
285             xInfoBox.execute();
286         }
287         catch(java.lang.Throwable exIgnore)
288         {
289             // ignore any problem, which can occur here.
290             // It's not really a bug for this example job, if
291             // it's message could not be printed out!
292         }
293     }
294 
295     //___________________________________________
296 
297     private void showInfoNonModal( java.lang.String sTitle   ,
298                                    java.lang.String sMessage )
299     {
300         // Couldnt be implemented really using the toolkit ...
301         // Because we need a parent anytime.
302         // And showing e.g. a java dialog can make some trouble
303         // inside office ... but we have no chance here.
304 	final java.lang.String sFinalTitle = sTitle;
305 	final java.lang.String sFinalMessage = sMessage;
306 
307 	// On Mac OS X, AWT/Swing must not be accessed from the AppKit thread, so call
308 	// SwingUtilities.invokeLater always on a fresh thread to avoid that problem
309 	// (also, the current thread must not wait for that fresh thread to terminate,
310 	// as that would cause a deadlock if this thread is the AppKit thread):
311 	final Runnable doRun = new Runnable() {
312 		public void run() {
313 		    javax.swing.JOptionPane.showMessageDialog(null, sFinalMessage, sFinalTitle, javax.swing.JOptionPane.INFORMATION_MESSAGE);
314 		}
315 	    };
316 
317 	 new Thread( doRun ) {
318 	     public void run() { javax.swing.SwingUtilities.invokeLater(doRun); }
319 	 }.start();
320     }
321 
322     //___________________________________________
323 
324     /** helper to print out the given argument list.
325      *
326      *  @param  lGenericConfig
327      *          contains all shared configuration items for a job
328      *
329      *  @param  lJobConfig
330      *          contains all job sepcific configuration items
331      *
332      *  @param  lEnvironment
333      *          contains some environment informations
334      *
335      *  @param  lDynamicData
336      *          contains optional data of a might corresponding dispatch() request
337      */
338 
339     private java.lang.String formatOutArgs(com.sun.star.beans.NamedValue[] lGenericConfig,
340                                            com.sun.star.beans.NamedValue[] lJobConfig    ,
341                                            com.sun.star.beans.NamedValue[] lEnvironment  ,
342                                            com.sun.star.beans.NamedValue[] lDynamicData )
343     {
344         java.lang.StringBuffer sOut = new java.lang.StringBuffer(1024);
345 
346         sOut.append("list \"Config\": ");
347         if (lGenericConfig==null)
348             sOut.append("0 items\n");
349         else
350         {
351             int c = lGenericConfig.length;
352             sOut.append(c+" items\n");
353             for (int i=0; i<c; ++i)
354                 sOut.append("\t["+i+"] \""+lGenericConfig[i].Name+"\" = {"+lGenericConfig[i].Value+"}\n");
355         }
356         sOut.append("list \"JobConfig\": ");
357         if (lJobConfig==null)
358             sOut.append("0 items\n");
359         else
360         {
361             int c = lJobConfig.length;
362             sOut.append(c+" items\n");
363             for (int i=0; i<c; ++i)
364                 sOut.append("\t["+i+"] \""+lJobConfig[i].Name+"\" = {"+lJobConfig[i].Value+"}\n");
365         }
366         sOut.append("list \"Environment\": ");
367         if (lEnvironment==null)
368             sOut.append("0 items\n");
369         else
370         {
371             int c = lEnvironment.length;
372             sOut.append(c+" items\n");
373             for (int i=0; i<c; ++i)
374                 sOut.append("\t["+i+"] \""+lEnvironment[i].Name+"\" = {"+lEnvironment[i].Value+"}\n");
375         }
376         sOut.append("list \"DynamicData\": ");
377         if (lDynamicData==null)
378             sOut.append("0 items\n");
379         else
380         {
381             int c = lDynamicData.length;
382             sOut.append(c+" items\n");
383             for (int i=0; i<c; ++i)
384                 sOut.append("\t["+i+"] \""+lDynamicData[i].Name+"\" = {"+lDynamicData[i].Value+"}\n");
385         }
386 
387         return sOut.toString();
388     }
389 
390     public String[] getSupportedServiceNames() {
391         return SERVICENAMES;
392     }
393 
394     public boolean supportsService( String sService ) {
395         int len = SERVICENAMES.length;
396 
397         for( int i=0; i < len; i++) {
398             if ( sService.equals( SERVICENAMES[i] ) )
399                 return true;
400         }
401 
402         return false;
403     }
404 
405     public String getImplementationName() {
406         return( AsyncJob.class.getName() );
407     }
408 
409 
410     //___________________________________________
411 
412     public synchronized static com.sun.star.lang.XSingleComponentFactory __getComponentFactory(java.lang.String sImplName)
413     {
414         com.sun.star.lang.XSingleComponentFactory xFactory = null;
415         if (sImplName.equals(AsyncJob.IMPLEMENTATIONNAME))
416             xFactory = Factory.createComponentFactory(AsyncJob.class, SERVICENAMES);
417 
418         return xFactory;
419     }
420 
421     //___________________________________________
422     // This method not longer necessary since OOo 3.4 where the component registration
423     // was changed to passive component registration. For more details see
424     // http://wiki.services.openoffice.org/wiki/Passive_Component_Registration
425 
426 //     public synchronized static boolean __writeRegistryServiceInfo(com.sun.star.registry.XRegistryKey xRegKey)
427 //     {
428 //         return Factory.writeRegistryServiceInfo(
429 //             AsyncJob.IMPLEMENTATIONNAME,
430 //             AsyncJob.SERVICENAMES,
431 //             xRegKey);
432 //     }
433 }
434