KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > service > ServiceDispatcher


1 /*
2  * $Id: ServiceDispatcher.java 7284 2006-04-12 18:39:42Z jaz $
3  *
4  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  */

25 package org.ofbiz.service;
26
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Locale JavaDoc;
30 import java.util.Map JavaDoc;
31 import javax.transaction.Transaction JavaDoc;
32
33 import javolution.util.FastList;
34 import javolution.util.FastMap;
35 import org.apache.commons.collections.map.LRUMap;
36 import org.w3c.dom.Element JavaDoc;
37
38 import org.ofbiz.base.config.GenericConfigException;
39 import org.ofbiz.base.util.Debug;
40 import org.ofbiz.base.util.UtilMisc;
41 import org.ofbiz.base.util.UtilTimer;
42 import org.ofbiz.base.util.UtilValidate;
43 import org.ofbiz.base.util.UtilXml;
44 import org.ofbiz.entity.GenericDelegator;
45 import org.ofbiz.entity.GenericEntityException;
46 import org.ofbiz.entity.GenericValue;
47 import org.ofbiz.entity.transaction.DebugXaResource;
48 import org.ofbiz.entity.transaction.GenericTransactionException;
49 import org.ofbiz.entity.transaction.TransactionUtil;
50 import org.ofbiz.security.Security;
51 import org.ofbiz.security.SecurityConfigurationException;
52 import org.ofbiz.security.SecurityFactory;
53 import org.ofbiz.service.config.ServiceConfigUtil;
54 import org.ofbiz.service.eca.ServiceEcaUtil;
55 import org.ofbiz.service.engine.GenericEngine;
56 import org.ofbiz.service.engine.GenericEngineFactory;
57 import org.ofbiz.service.group.ServiceGroupReader;
58 import org.ofbiz.service.jms.JmsListenerFactory;
59 import org.ofbiz.service.job.JobManager;
60 import org.ofbiz.service.job.JobManagerException;
61
62 /**
63  * Global Service Dispatcher
64  *
65  * @author <a HREF="mailto:jaz@ofbiz.org">Andy Zeneski</a>
66  * @version $Rev: 7284 $
67  * @since 2.0
68  */

69 public class ServiceDispatcher {
70
71     public static final String JavaDoc module = ServiceDispatcher.class.getName();
72     public static final int lruLogSize = 200;
73
74     protected static Map JavaDoc runLog = new LRUMap(lruLogSize);
75     protected static Map JavaDoc dispatchers = FastMap.newInstance();
76     protected static boolean enableJM = true;
77     protected static boolean enableJMS = true;
78     protected static boolean enableSvcs = true;
79
80     protected GenericDelegator delegator = null;
81     protected GenericEngineFactory factory = null;
82     protected Security security = null;
83     protected Map JavaDoc localContext = null;
84     protected Map JavaDoc callbacks = null;
85     protected JobManager jm = null;
86     protected JmsListenerFactory jlf = null;
87
88     public ServiceDispatcher(GenericDelegator delegator, boolean enableJM, boolean enableJMS, boolean enableSvcs) {
89         Debug.logInfo("[ServiceDispatcher] : Creating new instance.", module);
90         factory = new GenericEngineFactory(this);
91         ServiceGroupReader.readConfig();
92         ServiceEcaUtil.readConfig();
93
94         this.delegator = delegator;
95         this.localContext = FastMap.newInstance();
96         this.callbacks = FastMap.newInstance();
97
98         if (delegator != null) {
99             try {
100                 this.security = SecurityFactory.getInstance(delegator);
101             } catch (SecurityConfigurationException e) {
102                 Debug.logError(e, "[ServiceDispatcher.init] : No instance of security imeplemtation found.", module);
103             }
104         }
105
106         // make sure we haven't disabled these features from running
107
if (enableJM) {
108             this.jm = new JobManager(this.delegator);
109         }
110
111         if (enableJMS) {
112             this.jlf = new JmsListenerFactory(this);
113         }
114
115         if (enableSvcs) {
116             this.runStartupServices();
117         }
118     }
119
120     public ServiceDispatcher(GenericDelegator delegator) {
121         this(delegator, enableJM, enableJMS, enableSvcs);
122     }
123
124     /**
125      * Returns a pre-registered instance of the ServiceDispatcher associated with this delegator.
126      * @param delegator the local delegator
127      * @return A reference to this global ServiceDispatcher
128      */

129     public static ServiceDispatcher getInstance(String JavaDoc name, GenericDelegator delegator) {
130         ServiceDispatcher sd = getInstance(null, null, delegator);
131
132         if (!sd.containsContext(name)) {
133             return null;
134         }
135         return sd;
136     }
137
138     /**
139      * Returns an instance of the ServiceDispatcher associated with this delegator and registers the loader.
140      * @param name the local dispatcher
141      * @param context the context of the local dispatcher
142      * @param delegator the local delegator
143      * @return A reference to this global ServiceDispatcher
144      */

145     public static ServiceDispatcher getInstance(String JavaDoc name, DispatchContext context, GenericDelegator delegator) {
146         ServiceDispatcher sd = null;
147
148         String JavaDoc dispatcherKey = delegator != null ? delegator.getDelegatorName() : "null";
149         sd = (ServiceDispatcher) dispatchers.get(dispatcherKey);
150         if (sd == null) {
151             synchronized (ServiceDispatcher.class) {
152                 if (Debug.verboseOn()) Debug.logVerbose("[ServiceDispatcher.getInstance] : No instance found (" + delegator.getDelegatorName() + ").", module);
153                 sd = (ServiceDispatcher) dispatchers.get(dispatcherKey);
154                 if (sd == null) {
155                     sd = new ServiceDispatcher(delegator);
156                     dispatchers.put(dispatcherKey, sd);
157                 }
158             }
159         }
160         if (name != null && context != null) {
161             sd.register(name, context);
162         }
163         return sd;
164     }
165
166     /**
167      * Registers the loader with this ServiceDispatcher
168      * @param name the local dispatcher
169      * @param context the context of the local dispatcher
170      */

171     public void register(String JavaDoc name, DispatchContext context) {
172         if (Debug.infoOn()) Debug.logInfo("Registered dispatcher: " + context.getName(), module);
173         this.localContext.put(name, context);
174     }
175
176     /**
177      * De-Registers the loader with this ServiceDispatcher
178      * @param local the LocalDispatcher to de-register
179      */

180     public void deregister(LocalDispatcher local) {
181         if (Debug.infoOn()) Debug.logInfo("De-Registering dispatcher: " + local.getName(), module);
182         localContext.remove(local.getName());
183          if (localContext.size() == 1) { // 1 == the JMSDispatcher
184
try {
185                  this.shutdown();
186              } catch (GenericServiceException e) {
187                  Debug.logError(e, "Trouble shutting down ServiceDispatcher!", module);
188              }
189          }
190     }
191
192     public synchronized void registerCallback(String JavaDoc serviceName, GenericServiceCallback cb) {
193         List JavaDoc callBackList = (List JavaDoc) callbacks.get(serviceName);
194         if (callBackList == null) {
195             callBackList = FastList.newInstance();
196         }
197         callBackList.add(cb);
198         callbacks.put(serviceName, callBackList);
199     }
200
201     public List JavaDoc getCallbacks(String JavaDoc serviceName) {
202         return (List JavaDoc) callbacks.get(serviceName);
203     }
204
205     /**
206      * Run the service synchronously and return the result.
207      * @param localName Name of the context to use.
208      * @param service Service model object.
209      * @param context Map of name, value pairs composing the context.
210      * @return Map of name, value pairs composing the result.
211      * @throws ServiceAuthException
212      * @throws ServiceValidationException
213      * @throws GenericServiceException
214      */

215     public Map JavaDoc runSync(String JavaDoc localName, ModelService service, Map JavaDoc context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
216         return runSync(localName, service, context, true);
217     }
218
219     /**
220      * Run the service synchronously and IGNORE the result.
221      * @param localName Name of the context to use.
222      * @param service Service model object.
223      * @param context Map of name, value pairs composing the context.
224      * @throws ServiceAuthException
225      * @throws ServiceValidationException
226      * @throws GenericServiceException
227      */

228     public void runSyncIgnore(String JavaDoc localName, ModelService service, Map JavaDoc context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
229         runSync(localName, service, context, false);
230     }
231
232     /**
233      * Run the service synchronously and return the result.
234      * @param localName Name of the context to use.
235      * @param modelService Service model object.
236      * @param context Map of name, value pairs composing the context.
237      * @param validateOut Validate OUT parameters
238      * @return Map of name, value pairs composing the result.
239      * @throws ServiceAuthException
240      * @throws ServiceValidationException
241      * @throws GenericServiceException
242      */

243     public Map JavaDoc runSync(String JavaDoc localName, ModelService modelService, Map JavaDoc context, boolean validateOut) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
244         UtilTimer timer = null;
245         if (Debug.timingOn()) {
246             timer = new UtilTimer(localName + " / " + modelService.name, true);
247             // not thread safe: UtilTimer.timerLog(localName + " / " + modelService.name, "Sync service started...", module);
248
}
249         boolean debugging = checkDebug(modelService, 1, true);
250         if (Debug.verboseOn()) {
251             Debug.logVerbose("[ServiceDispatcher.runSync] : invoking service " + modelService.name + " [" + modelService.location +
252                 "/" + modelService.invoke + "] (" + modelService.engineName + ")", module);
253         }
254
255         // setup the result map
256
Map JavaDoc result = FastMap.newInstance();
257         boolean isFailure = false;
258         boolean isError = false;
259
260         // set up the running service log
261
RunningService rs = this.logService(localName, modelService, GenericEngine.SYNC_MODE);
262
263         // get eventMap once for all calls for speed, don't do event calls if it is null
264
Map JavaDoc eventMap = ServiceEcaUtil.getServiceEventMap(modelService.name);
265
266         // check the locale
267
Locale JavaDoc locale = this.checkLocale(context);
268
269         // setup the engine and context
270
DispatchContext ctx = (DispatchContext) localContext.get(localName);
271         GenericEngine engine = this.getGenericEngine(modelService.engineName);
272
273         Map JavaDoc ecaContext = null;
274
275         // for isolated transactions
276
Transaction JavaDoc parentTransaction = null;
277
278         // start the transaction
279
boolean beganTrans = false;
280         try {
281             if (modelService.useTransaction) {
282                 beganTrans = TransactionUtil.begin(modelService.transactionTimeout);
283                 // isolate the transaction if defined
284
if (modelService.requireNewTransaction && !beganTrans) {
285                     parentTransaction = TransactionUtil.suspend();
286                     // now start a new transaction
287
beganTrans = TransactionUtil.begin(modelService.transactionTimeout);
288                 }
289             }
290
291             // XAResource debugging
292
if (beganTrans && TransactionUtil.debugResources) {
293                 DebugXaResource dxa = new DebugXaResource(modelService.name);
294                 try {
295                     dxa.enlist();
296                 } catch (Exception JavaDoc e) {
297                     Debug.logError(e, module);
298                 }
299             }
300
301             try {
302                 // setup global transaction ECA listeners
303
if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-rollback", ctx, context, result, false, false);
304                 if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-commit", ctx, context, result, false, false);
305
306                 // pre-auth ECA
307
if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "auth", ctx, context, result, false, false);
308
309                 context = checkAuth(localName, context, modelService);
310                 Object JavaDoc userLogin = context.get("userLogin");
311
312                 if (modelService.auth && userLogin == null) {
313                     throw new ServiceAuthException("User authorization is required for this service: " + modelService.name + modelService.debugInfo());
314                 }
315
316                 // pre-validate ECA
317
if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "in-validate", ctx, context, result, false, false);
318
319                 // check for pre-validate failure/erros
320
isFailure = ModelService.RESPOND_FAIL.equals(result.get(ModelService.RESPONSE_MESSAGE));
321                 isError = ModelService.RESPOND_ERROR.equals(result.get(ModelService.RESPONSE_MESSAGE));
322
323                 // validate the context
324
if (modelService.validate && !isError && !isFailure) {
325                     try {
326                         modelService.validate(context, ModelService.IN_PARAM, locale);
327                     } catch (ServiceValidationException e) {
328                         Debug.logError(e, "Incoming context (in runSync : " + modelService.name + ") does not match expected requirements", module);
329                         throw e;
330                     }
331                 }
332
333                 // pre-invoke ECA
334
if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "invoke", ctx, context, result, false, false);
335
336                 // check for pre-invoke failure/erros
337
isFailure = ModelService.RESPOND_FAIL.equals(result.get(ModelService.RESPONSE_MESSAGE));
338                 isError = ModelService.RESPOND_ERROR.equals(result.get(ModelService.RESPONSE_MESSAGE));
339
340                 // ===== invoke the service =====
341
if (!isError && !isFailure) {
342                     Map JavaDoc invokeResult = engine.runSync(localName, modelService, context);
343                     engine.sendCallbacks(modelService, context, invokeResult, GenericEngine.SYNC_MODE);
344                     if (invokeResult != null) {
345                         result.putAll(invokeResult);
346                     } else {
347                         Debug.logWarning("Service (in runSync : " + modelService.name + ") returns null result", module);
348                     }
349                 }
350
351                 // re-check the errors/failures
352
isFailure = ModelService.RESPOND_FAIL.equals(result.get(ModelService.RESPONSE_MESSAGE));
353                 isError = ModelService.RESPOND_ERROR.equals(result.get(ModelService.RESPONSE_MESSAGE));
354
355                 // create a new context with the results to pass to ECA services; necessary because caller may reuse this context
356
ecaContext = FastMap.newInstance();
357                 ecaContext.putAll(context);
358
359                 // copy all results: don't worry parameters that aren't allowed won't be passed to the ECA services
360
ecaContext.putAll(result);
361
362                 // validate the result
363
if (modelService.validate && validateOut) {
364                     // pre-out-validate ECA
365
if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "out-validate", ctx, ecaContext, result, isError, isFailure);
366                     try {
367                         modelService.validate(result, ModelService.OUT_PARAM, locale);
368                     } catch (ServiceValidationException e) {
369                         Debug.logError(e, "Outgoing result (in runSync : " + modelService.name + ") does not match expected requirements", module);
370                         throw e;
371                     }
372                 }
373
374                 // pre-commit ECA
375
if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "commit", ctx, ecaContext, result, isError, isFailure);
376
377                 // check for failure and log on info level; this is used for debugging
378
if (isFailure) {
379                     Debug.logWarning("Service Failure [" + modelService.name + "]: " + ServiceUtil.getErrorMessage(result), module);
380                 }
381
382             } catch (Throwable JavaDoc t) {
383                 if (Debug.timingOn()) {
384                     UtilTimer.closeTimer(localName + " / " + modelService.name, "Sync service failed...", module);
385                 }
386                 String JavaDoc errMsg = "Service [" + modelService.name + "] threw an unexpected exception/error";
387                 Debug.logError(t, errMsg, module);
388                 engine.sendCallbacks(modelService, context, t, GenericEngine.SYNC_MODE);
389                 try {
390                     TransactionUtil.rollback(beganTrans, errMsg, t);
391                 } catch (GenericTransactionException te) {
392                     Debug.logError(te, "Cannot rollback transaction", module);
393                 }
394                 checkDebug(modelService, 0, debugging);
395                 rs.setEndStamp();
396                 if (t instanceof ServiceAuthException) {
397                     throw (ServiceAuthException) t;
398                 } else if (t instanceof ServiceValidationException) {
399                     throw (ServiceValidationException) t;
400                 } else if (t instanceof GenericServiceException) {
401                     throw (GenericServiceException) t;
402                 } else {
403                     throw new GenericServiceException("Service [" + modelService.name + "] Failed" + modelService.debugInfo() , t);
404                 }
405             } finally {
406                 // if there was an error, rollback transaction, otherwise commit
407
if (isError) {
408                     String JavaDoc errMsg = "Service Error [" + modelService.name + "]: " + ServiceUtil.getErrorMessage(result);
409                     // try to log the error
410
Debug.logError(errMsg, module);
411
412                     // rollback the transaction
413
try {
414                         TransactionUtil.rollback(beganTrans, errMsg, null);
415                     } catch (GenericTransactionException e) {
416                         Debug.logError(e, "Could not rollback transaction: " + e.toString(), module);
417                     }
418                 } else {
419                     // commit the transaction
420
try {
421                         TransactionUtil.commit(beganTrans);
422                     } catch (GenericTransactionException e) {
423                         String JavaDoc errMsg = "Could not commit transaction for service [" + modelService.name + "] call";
424                         Debug.logError(e, errMsg, module);
425                         if (e.getMessage() != null) {
426                             errMsg = errMsg + ": " + e.getMessage();
427                         }
428                         throw new GenericServiceException(errMsg);
429                     }
430                 }
431             }
432         } catch (GenericTransactionException te) {
433             Debug.logError(te, "Problems with the transaction", module);
434             throw new GenericServiceException("Problems with the transaction.", te.getNested());
435         } finally {
436             // resume the parent transaction
437
if (parentTransaction != null) {
438                 try {
439                     TransactionUtil.resume(parentTransaction);
440                 } catch (GenericTransactionException ite) {
441                     Debug.logWarning(ite, "Transaction error, not resumed", module);
442                     throw new GenericServiceException("Resume transaction exception, see logs");
443                 }
444             }
445         }
446
447         // pre-return ECA
448
if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "return", ctx, ecaContext, result, isError, isFailure);
449
450         checkDebug(modelService, 0, debugging);
451         rs.setEndStamp();
452         if (timer != null) {
453             timer.setLog(true);
454             timer.timerString("Sync service finished", module);
455         }
456         return result;
457     }
458
459     /**
460      * Run the service asynchronously, passing an instance of GenericRequester that will receive the result.
461      * @param localName Name of the context to use.
462      * @param service Service model object.
463      * @param context Map of name, value pairs composing the context.
464      * @param requester Object implementing GenericRequester interface which will receive the result.
465      * @param persist True for store/run; False for run.
466      * @throws ServiceAuthException
467      * @throws ServiceValidationException
468      * @throws GenericServiceException
469      */

470     public void runAsync(String JavaDoc localName, ModelService service, Map JavaDoc context, GenericRequester requester, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
471         if (Debug.timingOn()) {
472             UtilTimer.timerLog(localName + " / " + service.name, "ASync service started...", module);
473         }
474         boolean debugging = checkDebug(service, 1, true);
475         if (Debug.verboseOn()) {
476             Debug.logVerbose("[ServiceDispatcher.runAsync] : prepareing service " + service.name + " [" + service.location + "/" + service.invoke +
477                 "] (" + service.engineName + ")", module);
478         }
479
480         // setup the result map
481
Map JavaDoc result = FastMap.newInstance();
482         boolean isFailure = false;
483         boolean isError = false;
484
485         // set up the running service log
486
this.logService(localName, service, GenericEngine.ASYNC_MODE);
487
488         // check the locale
489
Locale JavaDoc locale = this.checkLocale(context);
490
491         // setup the engine and context
492
DispatchContext ctx = (DispatchContext) localContext.get(localName);
493         GenericEngine engine = this.getGenericEngine(service.engineName);
494
495         // for isolated transactions
496
Transaction JavaDoc parentTransaction = null;
497         // start the transaction
498
boolean beganTrans = false;
499
500         try {
501             if (service.useTransaction) {
502                 beganTrans = TransactionUtil.begin(service.transactionTimeout);
503
504                 // isolate the transaction if defined
505
if (service.requireNewTransaction && !beganTrans) {
506                     parentTransaction = TransactionUtil.suspend();
507                     // now start a new transaction
508
beganTrans = TransactionUtil.begin(service.transactionTimeout);
509                 }
510             }
511
512             // XAResource debugging
513
if (beganTrans && TransactionUtil.debugResources) {
514                 DebugXaResource dxa = new DebugXaResource(service.name);
515                 try {
516                     dxa.enlist();
517                 } catch (Exception JavaDoc e) {
518                     Debug.logError(e, module);
519                 }
520             }
521
522             try {
523                 // get eventMap once for all calls for speed, don't do event calls if it is null
524
Map JavaDoc eventMap = ServiceEcaUtil.getServiceEventMap(service.name);
525
526                 // pre-auth ECA
527
if (eventMap != null) ServiceEcaUtil.evalRules(service.name, eventMap, "auth", ctx, context, result, isError, isFailure);
528
529                 context = checkAuth(localName, context, service);
530                 Object JavaDoc userLogin = context.get("userLogin");
531
532                 if (service.auth && userLogin == null)
533                     throw new ServiceAuthException("User authorization is required for this service: " + service.name + service.debugInfo());
534
535                 // pre-validate ECA
536
if (eventMap != null) ServiceEcaUtil.evalRules(service.name, eventMap, "in-validate", ctx, context, result, isError, isFailure);
537
538                 // check for pre-validate failure/errors
539
isFailure = ModelService.RESPOND_FAIL.equals(result.get(ModelService.RESPONSE_MESSAGE));
540                 isError = ModelService.RESPOND_ERROR.equals(result.get(ModelService.RESPONSE_MESSAGE));
541
542                 // validate the context
543
if (service.validate && !isError && !isFailure) {
544                     try {
545                         service.validate(context, ModelService.IN_PARAM, locale);
546                     } catch (ServiceValidationException e) {
547                         Debug.logError(e, "Incoming service context (in runAsync: " + service.name + ") does not match expected requirements", module);
548                         throw e;
549                     }
550                 }
551
552                 // run the service
553
if (!isError && !isFailure) {
554                     if (requester != null) {
555                         engine.runAsync(localName, service, context, requester, persist);
556                     } else {
557                         engine.runAsync(localName, service, context, persist);
558                     }
559                     engine.sendCallbacks(service, context, null, GenericEngine.ASYNC_MODE);
560                 }
561
562                 if (Debug.timingOn()) {
563                     UtilTimer.closeTimer(localName + " / " + service.name, "ASync service finished...", module);
564                 }
565                 checkDebug(service, 0, debugging);
566             } catch (Throwable JavaDoc t) {
567                 if (Debug.timingOn()) {
568                     UtilTimer.closeTimer(localName + " / " + service.name, "ASync service failed...", module);
569                 }
570                 String JavaDoc errMsg = "Service [" + service.name + "] threw an unexpected exception/error";
571                 Debug.logError(t, errMsg, module);
572                 engine.sendCallbacks(service, context, t, GenericEngine.ASYNC_MODE);
573                 try {
574                     TransactionUtil.rollback(beganTrans, errMsg, t);
575                 } catch (GenericTransactionException te) {
576                     Debug.logError(te, "Cannot rollback transaction", module);
577                 }
578                 checkDebug(service, 0, debugging);
579                 if (t instanceof ServiceAuthException) {
580                     throw (ServiceAuthException) t;
581                 } else if (t instanceof ServiceValidationException) {
582                     throw (ServiceValidationException) t;
583                 } else if (t instanceof GenericServiceException) {
584                     throw (GenericServiceException) t;
585                 } else {
586                     throw new GenericServiceException("Service [" + service.name + "] Failed" + service.debugInfo() , t);
587                 }
588             } finally {
589                 // always try to commit the transaction since we don't know in this case if its was an error or not
590
try {
591                     TransactionUtil.commit(beganTrans);
592                 } catch (GenericTransactionException e) {
593                     Debug.logError(e, "Could not commit transaction", module);
594                     throw new GenericServiceException("Commit transaction failed");
595                 }
596             }
597         } catch (GenericTransactionException se) {
598             Debug.logError(se, "Problems with the transaction", module);
599             throw new GenericServiceException("Problems with the transaction: " + se.getMessage() + "; See logs for more detail");
600         } finally {
601             // resume the parent transaction
602
if (parentTransaction != null) {
603                 try {
604                     TransactionUtil.resume(parentTransaction);
605                 } catch (GenericTransactionException ise) {
606                     Debug.logError(ise, "Trouble resuming parent transaction", module);
607                     throw new GenericServiceException("Resume transaction exception: " + ise.getMessage() + "; See logs for more detail");
608                 }
609             }
610         }
611     }
612
613     /**
614      * Run the service asynchronously and IGNORE the result.
615      * @param localName Name of the context to use.
616      * @param service Service model object.
617      * @param context Map of name, value pairs composing the context.
618      * @param persist True for store/run; False for run.
619      * @throws ServiceAuthException
620      * @throws ServiceValidationException
621      * @throws GenericServiceException
622      */

623     public void runAsync(String JavaDoc localName, ModelService service, Map JavaDoc context, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
624         this.runAsync(localName, service, context, null, persist);
625     }
626
627     /**
628      * Gets the GenericEngine instance that corresponds to the given name
629      * @param engineName Name of the engine
630      * @return GenericEngine instance that corresponds to the engineName
631      */

632     public GenericEngine getGenericEngine(String JavaDoc engineName) throws GenericServiceException {
633         return factory.getGenericEngine(engineName);
634     }
635
636     /**
637      * Gets the JobManager associated with this dispatcher
638      * @return JobManager that is associated with this dispatcher
639      */

640     public JobManager getJobManager() {
641         return this.jm;
642     }
643
644     /**
645      * Gets the JmsListenerFactory which holds the message listeners.
646      * @return JmsListenerFactory
647      */

648     public JmsListenerFactory getJMSListenerFactory() {
649         return this.jlf;
650     }
651
652     /**
653      * Gets the GenericDelegator associated with this dispatcher
654      * @return GenericDelegator associated with this dispatcher
655      */

656     public GenericDelegator getDelegator() {
657         return this.delegator;
658     }
659
660     /**
661      * Gets the Security object associated with this dispatcher
662      * @return Security object associated with this dispatcher
663      */

664     public Security getSecurity() {
665         return this.security;
666     }
667
668     /**
669      * Gets the local context from a name
670      * @param name of the context to find.
671      */

672     public DispatchContext getLocalContext(String JavaDoc name) {
673         return (DispatchContext) localContext.get(name);
674     }
675
676     /**
677      * Gets the local dispatcher from a name
678      * @param name of the LocalDispatcher to find.
679      * @return LocalDispatcher matching the loader name
680      */

681     public LocalDispatcher getLocalDispatcher(String JavaDoc name) {
682         return ((DispatchContext) localContext.get(name)).getDispatcher();
683     }
684
685     /**
686      * Test if this dispatcher instance contains the local context.
687      * @param name of the local context
688      * @return true if the local context is found in this dispatcher.
689      */

690     public boolean containsContext(String JavaDoc name) {
691         return localContext.containsKey(name);
692     }
693
694     protected void shutdown() throws GenericServiceException {
695         Debug.logImportant("Shutting down the service engine...", module);
696         // shutdown JMS listeners
697
jlf.closeListeners();
698         // shutdown the job scheduler
699
jm.finalize();
700     }
701
702     // checks if parameters were passed for authentication
703
private Map JavaDoc checkAuth(String JavaDoc localName, Map JavaDoc context, ModelService origService) throws ServiceAuthException, GenericServiceException {
704         String JavaDoc service = ServiceConfigUtil.getElementAttr("authorization", "service-name");
705
706         if (service == null) {
707             throw new GenericServiceException("No Authentication Service Defined");
708         }
709         if (service.equals(origService.name)) {
710             // manually calling the auth service, don't continue...
711
return context;
712         }
713
714         if (context.containsKey("login.username")) {
715             // check for a username/password, if there log the user in and make the userLogin object
716
String JavaDoc username = (String JavaDoc) context.get("login.username");
717
718             if (context.containsKey("login.password")) {
719                 String JavaDoc password = (String JavaDoc) context.get("login.password");
720
721                 context.put("userLogin", getLoginObject(service, localName, username, password, (Locale JavaDoc) context.get("locale")));
722                 context.remove("login.password");
723             } else {
724                 context.put("userLogin", getLoginObject(service, localName, username, null, (Locale JavaDoc) context.get("locale")));
725             }
726             context.remove("login.username");
727         } else {
728             // if a userLogin object is there, make sure the given username/password exists in our local database
729
GenericValue userLogin = (GenericValue) context.get("userLogin");
730
731             if (userLogin != null) {
732                 // Because of encrypted passwords we can't just pass in the encrypted version of the password from the data, so we'll do something different and not run the userLogin service...
733

734                 //The old way: GenericValue newUserLogin = getLoginObject(service, localName, userLogin.getString("userLoginId"), userLogin.getString("currentPassword"), (Locale) context.get("locale"));
735
GenericValue newUserLogin = null;
736                 try {
737                     newUserLogin = this.getDelegator().findByPrimaryKeyCache("UserLogin", UtilMisc.toMap("userLoginId", userLogin.get("userLoginId")));
738                 } catch (GenericEntityException e) {
739                     Debug.logError(e, "Error looking up service authentication UserLogin: " + e.toString(), module);
740                     // leave newUserLogin null, will be handled below
741
}
742
743                 if (newUserLogin == null) {
744                     // uh oh, couldn't validate that one...
745
// we'll have to remove it from the incoming context which will cause an auth error later if auth is required
746
Debug.logInfo("Service auth failed for userLoginId [" + userLogin.get("userLoginId") + "] because UserLogin record not found.", module);
747                     context.remove("userLogin");
748                 } else if (newUserLogin.getString("currentPassword") != null && !newUserLogin.getString("currentPassword").equals(userLogin.getString("currentPassword"))) {
749                     // passwords didn't match, remove the userLogin for failed auth
750
Debug.logInfo("Service auth failed for userLoginId [" + userLogin.get("userLoginId") + "] because UserLogin record currentPassword fields did not match; note that the UserLogin object passed into a service may need to have the currentPassword encrypted.", module);
751                     context.remove("userLogin");
752                 }
753             }
754         }
755
756         // evaluate permissions for the service or throw exception if fail.
757
DispatchContext dctx = this.getLocalContext(localName);
758         GenericValue userLogin = (GenericValue) context.get("userLogin");
759         if (!origService.evalPermissions(dctx.getSecurity(), userLogin)) {
760             throw new ServiceAuthException("You do not have permission to invoke this service");
761         }
762
763         return context;
764     }
765
766     // gets a value object from name/password pair
767
private GenericValue getLoginObject(String JavaDoc service, String JavaDoc localName, String JavaDoc username, String JavaDoc password, Locale JavaDoc locale) throws GenericServiceException {
768         Map JavaDoc context = UtilMisc.toMap("login.username", username, "login.password", password, "isServiceAuth", new Boolean JavaDoc(true), "locale", locale);
769
770         if (Debug.verboseOn()) Debug.logVerbose("[ServiceDispathcer.authenticate] : Invoking UserLogin Service", module);
771
772         // get the dispatch context and service model
773
DispatchContext dctx = getLocalContext(localName);
774         ModelService model = dctx.getModelService(service);
775
776         // get the service engine
777
GenericEngine engine = getGenericEngine(model.engineName);
778
779         // invoke the service and get the UserLogin value object
780
Map JavaDoc result = engine.runSync(localName, model, context);
781         GenericValue value = (GenericValue) result.get("userLogin");
782
783         return value;
784     }
785
786     // checks the locale object in the context
787
private Locale JavaDoc checkLocale(Map JavaDoc context) {
788         Object JavaDoc locale = context.get("locale");
789         Locale JavaDoc newLocale = null;
790
791         if (locale != null) {
792             if (locale instanceof Locale JavaDoc) {
793                 return (Locale JavaDoc) locale;
794             } else if (locale instanceof String JavaDoc) {
795                 // en_US = lang_COUNTRY
796
newLocale = UtilMisc.parseLocale((String JavaDoc) locale);
797             }
798         }
799
800         if (newLocale == null) {
801             newLocale = Locale.getDefault();
802         }
803         context.put("locale", newLocale);
804         return newLocale;
805     }
806
807     // mode 1 = beginning (turn on) mode 0 = end (turn off)
808
private boolean checkDebug(ModelService model, int mode, boolean enable) {
809         boolean debugOn = Debug.verboseOn();
810         switch (mode) {
811             case 0:
812                 if (model.debug && enable && debugOn) {
813                     // turn it off
814
Debug.set(Debug.VERBOSE, false);
815                     Debug.logInfo("Verbose logging turned OFF", module);
816                     return true;
817                 }
818                 break;
819             case 1:
820                 if (model.debug && enable && !debugOn) {
821                     // turn it on
822
Debug.set(Debug.VERBOSE, true);
823                     Debug.logInfo("Verbose logging turned ON", module);
824                     return true;
825                 }
826                 break;
827             default:
828                 Debug.logError("Invalid mode for checkDebug should be (0 or 1)", module);
829         }
830         return false;
831     }
832
833     // run startup services
834
private synchronized int runStartupServices() {
835         if (jm == null) return 0;
836
837         Element JavaDoc root = null;
838         try {
839             root = ServiceConfigUtil.getXmlRootElement();
840         } catch (GenericConfigException e) {
841             Debug.logError(e, module);
842             return 0;
843         }
844
845         int servicesScheduled = 0;
846         List JavaDoc startupServices = UtilXml.childElementList(root, "startup-service");
847         if (startupServices != null && startupServices.size() > 0) {
848             Iterator JavaDoc i = startupServices.iterator();
849             while (i.hasNext()) {
850                 Element JavaDoc ss = (Element JavaDoc) i.next();
851                 String JavaDoc serviceName = ss.getAttribute("name");
852                 String JavaDoc runtimeDataId = ss.getAttribute("runtime-data-id");
853                 String JavaDoc delayStr = ss.getAttribute("runtime-delay");
854                 String JavaDoc sendToPool = ss.getAttribute("run-in-pool");
855                 if (UtilValidate.isEmpty(sendToPool)) {
856                     sendToPool = ServiceConfigUtil.getSendPool();
857                 }
858
859                 long runtimeDelay = 0;
860                 try {
861                     runtimeDelay = Long.parseLong(delayStr);
862                 } catch (Exception JavaDoc e) {
863                     Debug.logError(e, "Unable to parse runtime-delay value; using 0", module);
864                     runtimeDelay = 0;
865                 }
866
867                 // current time + 1 sec delay + extended delay
868
long runtime = System.currentTimeMillis() + 1000 + runtimeDelay;
869                 try {
870                     jm.schedule(sendToPool, serviceName, runtimeDataId, runtime);
871                 } catch (JobManagerException e) {
872                     Debug.logError(e, "Unable to schedule service [" + serviceName + "]", module);
873                 }
874             }
875         }
876
877         return servicesScheduled;
878     }
879
880     private RunningService logService(String JavaDoc localName, ModelService modelService, int mode) {
881         // set up the running service log
882
RunningService rs = new RunningService(localName, modelService, mode);
883         if (runLog == null) {
884             runLog = new LRUMap(lruLogSize);
885         }
886         try {
887             runLog.put(rs, this);
888         } catch (Throwable JavaDoc t) {
889             Debug.logWarning("LRUMap problem; resetting LRU [" + runLog.size() + "]", module);
890             runLog = new LRUMap(lruLogSize);
891             try {
892                 runLog.put(rs, this);
893             } catch (Throwable JavaDoc t2) {
894                 Debug.logError(t2, "Unable to put() in reset LRU map!", module);
895             }
896         }
897         return rs;
898     }
899
900     /**
901      * Enabled/Disables the Job Manager/Scheduler globally
902      * (this will not effect any dispatchers already running)
903      * @param enable
904      */

905     public static void enableJM(boolean enable) {
906         ServiceDispatcher.enableJM = enable;
907     }
908
909     /**
910      * Enabled/Disables the JMS listeners globally
911      * (this will not effect any dispatchers already running)
912      * @param enable
913      */

914     public static void enableJMS(boolean enable) {
915         ServiceDispatcher.enableJMS = enable;
916     }
917
918     /**
919      * Enabled/Disables the startup services globally
920      * (this will not effect any dispatchers already running)
921      * @param enable
922      */

923     public static void enableSvcs(boolean enable) {
924         ServiceDispatcher.enableSvcs = enable;
925     }
926
927     public static Map JavaDoc getServiceLogMap() {
928         return runLog;
929     }
930
931 }
932
Popular Tags