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 seems 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 seems 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 normally ... 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 // 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 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