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