cid#1606940 Check of thread-shared field evades lock acquisition
[LibreOffice.git] / odk / examples / DevelopersGuide / Components / Addons / JobsAddon / AsyncJob.java
blobc47244b9abbbf1310ca47ed87008fe68639cdd6b
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * The Contents of this file are made available subject to the terms of
5 * the BSD license.
7 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of Sun Microsystems, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *************************************************************************/
36 import com.sun.star.uno.XComponentContext;
37 import com.sun.star.lib.uno.helper.Factory;
38 import com.sun.star.lib.uno.helper.WeakBase;
39 import com.sun.star.lang.XServiceInfo;
40 import com.sun.star.task.*;
41 import com.sun.star.uno.*;
43 /** it implements a simple job component.
45 * Such jobs are executable in different ways:
46 * <ul>
47 * <li>registered for a special URL schema "vnd.sun.star.jobs:*" and used from the generic dispatch framework</li>
48 * <li>the global com.sun.star.task.JobExecutor service and registered for special events.</li>
49 * </ul>
51 public class AsyncJob extends WeakBase implements XServiceInfo, XAsyncJob
53 public final XComponentContext m_xCmpCtx;
55 /** the const list of supported uno service names. */
56 public static final String[] SERVICENAMES = {"com.sun.star.task.AsyncJob"};
58 /** the const uno implementation name.
59 * It must be a unique value! The best naming schema seems to use
60 * a registered domain in reverse order ...
62 public static final String IMPLEMENTATIONNAME = "com.sun.star.comp.framework.java.services.AsyncJob";
65 // interface
67 /** initialize a new instance of this class with default values. */
68 public AsyncJob( XComponentContext xCompContext )
70 m_xCmpCtx = xCompContext;
75 /** starts execution of this job.
77 * @param lArgs
78 * list which contains:
79 * <ul>
80 * <li>generic job configuration data</li>
81 * <li>job specific configuration data</li>
82 * <li>some environment information</li>
83 * <li>may optional arguments of a corresponding dispatch request</li>
84 * </ul>
86 * @params xListener
87 * callback to the executor of this job, which control our life time
89 * @throws com.sun.star.lang.IllegalArgumentException
90 * if given argument list seems to be wrong
92 public synchronized void executeAsync(com.sun.star.beans.NamedValue[] lArgs ,
93 com.sun.star.task.XJobListener xListener)
94 throws com.sun.star.lang.IllegalArgumentException
96 // For asynchronous jobs a valid listener reference is guaranteed normally ...
97 if (xListener == null)
98 throw new com.sun.star.lang.IllegalArgumentException("invalid listener");
100 // extract all possible sub list of given argument list
101 com.sun.star.beans.NamedValue[] lGenericConfig = null;
102 com.sun.star.beans.NamedValue[] lJobConfig = null;
103 com.sun.star.beans.NamedValue[] lEnvironment = null;
104 com.sun.star.beans.NamedValue[] lDynamicData = null;
106 int c = lArgs.length;
107 for (int i=0; i<c; ++i)
109 if (lArgs[i].Name.equals("Config"))
110 lGenericConfig = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
111 else
112 if (lArgs[i].Name.equals("JobConfig"))
113 lJobConfig = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
114 else
115 if (lArgs[i].Name.equals("Environment"))
116 lEnvironment = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
117 else
118 if (lArgs[i].Name.equals("DynamicData"))
119 lDynamicData = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(lArgs[i].Value);
122 // Analyze the environment info. This sub list is the only guaranteed one!
123 if (lEnvironment == null)
124 throw new com.sun.star.lang.IllegalArgumentException("no environment");
126 String sEnvType = null;
127 String sEventName = null;
128 com.sun.star.frame.XFrame xFrame = null;
129 c = lEnvironment.length;
130 for (int i=0; i<c; ++i)
132 if (lEnvironment[i].Name.equals("EnvType"))
133 sEnvType = com.sun.star.uno.AnyConverter.toString(lEnvironment[i].Value);
134 else
135 if (lEnvironment[i].Name.equals("EventName"))
136 sEventName = com.sun.star.uno.AnyConverter.toString(lEnvironment[i].Value);
137 else
138 if (lEnvironment[i].Name.equals("Frame"))
139 xFrame = (com.sun.star.frame.XFrame)com.sun.star.uno.AnyConverter.toObject(
140 new com.sun.star.uno.Type(com.sun.star.frame.XFrame.class),
141 lEnvironment[i].Value);
144 // Further the environment property "EnvType" is required as minimum.
145 if (
146 (sEnvType==null) ||
148 (!sEnvType.equals("EXECUTOR")) &&
149 (!sEnvType.equals("DISPATCH"))
153 String sMessage = "\"" + sEnvType + "\" isn't a valid value for EnvType";
154 throw new com.sun.star.lang.IllegalArgumentException(sMessage);
157 // Analyze the set of shared config data.
158 if (lGenericConfig!=null)
160 c = lGenericConfig.length;
161 for (int i=0; i<c; ++i)
163 if (lGenericConfig[i].Name.equals("Alias"))
164 com.sun.star.uno.AnyConverter.toString(lGenericConfig[i].Value);
168 // do your job ...
169 // Here we print out all found arguments.
170 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);
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;
182 // SaveArguments will be made everytimes!
183 c = 1;
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";
191 aSaveRequest = new com.sun.star.beans.NamedValue();
192 aSaveRequest.Name = "SaveArguments";
193 aSaveRequest.Value = lJobConfig;
195 // Deactivation is useful inside EXECUTOR environment only
196 if (sEnvType.equals("EXECUTOR"))
198 ++c;
199 aDeactivation = new com.sun.star.beans.NamedValue();
200 aDeactivation.Name = "Deactivate";
201 aDeactivation.Value = Boolean.TRUE;
204 // Sending of result events is useful inside DISPATCH environment only
205 if (sEnvType.equals("DISPATCH"))
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);
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;
222 xListener.jobFinished(this, lReturn);
227 /** show an info box with the UNO based toolkit.
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 its own thread...
237 * (see showInfoNonModal() too)
239 * @param xParent
240 * used as parent window of the shown info box.
242 * @param sTitle
243 * is shown as title of the info box.
245 * @param sMessage
246 * included the message body, which is shown as info.
249 private void showInfoModal( com.sun.star.awt.XWindow xParent ,
250 String sTitle ,
251 String sMessage )
255 // get access to the office toolkit environment
256 com.sun.star.awt.XToolkit xKit = UnoRuntime.queryInterface(
257 com.sun.star.awt.XToolkit.class,
258 m_xCmpCtx.getServiceManager().createInstanceWithContext("com.sun.star.awt.Toolkit",
259 m_xCmpCtx));
261 // describe the info box ini its 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 = UnoRuntime.queryInterface(
271 com.sun.star.awt.XWindowPeer.class,
272 xParent);
274 // create the info box window
275 com.sun.star.awt.XWindowPeer xPeer = xKit.createWindow(aDescriptor);
276 com.sun.star.awt.XMessageBox xInfoBox = UnoRuntime.queryInterface(
277 com.sun.star.awt.XMessageBox.class,
278 xPeer);
279 if (xInfoBox == null)
280 return;
282 // fill it with all given information and show it
283 xInfoBox.setCaptionText(sTitle);
284 xInfoBox.setMessageText(sMessage);
285 xInfoBox.execute();
287 catch(Throwable exIgnore)
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!
297 private void showInfoNonModal( String sTitle ,
298 String sMessage )
300 // Couldn't 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 String sFinalTitle = sTitle;
305 final String sFinalMessage = sMessage;
307 // On macOS, 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);
317 new Thread( doRun ) {
318 @Override
319 public void run() { javax.swing.SwingUtilities.invokeLater(doRun); }
320 }.start();
325 /** helper to print out the given argument list.
327 * @param lGenericConfig
328 * contains all shared configuration items for a job
330 * @param lJobConfig
331 * contains all job specific configuration items
333 * @param lEnvironment
334 * contains some environment information
336 * @param lDynamicData
337 * contains optional data of a might corresponding dispatch() request
340 private String formatOutArgs(com.sun.star.beans.NamedValue[] lGenericConfig,
341 com.sun.star.beans.NamedValue[] lJobConfig ,
342 com.sun.star.beans.NamedValue[] lEnvironment ,
343 com.sun.star.beans.NamedValue[] lDynamicData )
345 StringBuffer sOut = new StringBuffer(1024);
347 sOut.append("list \"Config\": ");
348 if (lGenericConfig==null)
349 sOut.append("0 items\n");
350 else
352 int c = lGenericConfig.length;
353 sOut.append(c+" items\n");
354 for (int i=0; i<c; ++i)
355 sOut.append("\t["+i+"] \""+lGenericConfig[i].Name+"\" = {"+lGenericConfig[i].Value+"}\n");
357 sOut.append("list \"JobConfig\": ");
358 if (lJobConfig==null)
359 sOut.append("0 items\n");
360 else
362 int c = lJobConfig.length;
363 sOut.append(c+" items\n");
364 for (int i=0; i<c; ++i)
365 sOut.append("\t["+i+"] \""+lJobConfig[i].Name+"\" = {"+lJobConfig[i].Value+"}\n");
367 sOut.append("list \"Environment\": ");
368 if (lEnvironment==null)
369 sOut.append("0 items\n");
370 else
372 int c = lEnvironment.length;
373 sOut.append(c+" items\n");
374 for (int i=0; i<c; ++i)
375 sOut.append("\t["+i+"] \""+lEnvironment[i].Name+"\" = {"+lEnvironment[i].Value+"}\n");
377 sOut.append("list \"DynamicData\": ");
378 if (lDynamicData==null)
379 sOut.append("0 items\n");
380 else
382 int c = lDynamicData.length;
383 sOut.append(c+" items\n");
384 for (int i=0; i<c; ++i)
385 sOut.append("\t["+i+"] \""+lDynamicData[i].Name+"\" = {"+lDynamicData[i].Value+"}\n");
388 return sOut.toString();
391 public String[] getSupportedServiceNames() {
392 return SERVICENAMES;
395 public boolean supportsService( String sService ) {
396 int len = SERVICENAMES.length;
398 for( int i=0; i < len; i++) {
399 if ( sService.equals( SERVICENAMES[i] ) )
400 return true;
403 return false;
406 public String getImplementationName() {
407 return( AsyncJob.class.getName() );
413 public synchronized static com.sun.star.lang.XSingleComponentFactory __getComponentFactory(String sImplName)
415 com.sun.star.lang.XSingleComponentFactory xFactory = null;
416 if (sImplName.equals(AsyncJob.IMPLEMENTATIONNAME))
417 xFactory = Factory.createComponentFactory(AsyncJob.class, SERVICENAMES);
419 return xFactory;
425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */