001: /*
002: * $Id: ServiceDispatcher.java,v 1.15 2004/02/19 18:52:35 ajzeneski Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.service;
026:
027: import java.util.HashMap;
028: import java.util.Locale;
029: import java.util.Map;
030:
031: import javax.transaction.InvalidTransactionException;
032: import javax.transaction.SystemException;
033: import javax.transaction.Transaction;
034: import javax.transaction.TransactionManager;
035:
036: import org.ofbiz.base.util.Debug;
037: import org.ofbiz.base.util.UtilMisc;
038: import org.ofbiz.entity.GenericDelegator;
039: import org.ofbiz.entity.GenericValue;
040: import org.ofbiz.entity.transaction.GenericTransactionException;
041: import org.ofbiz.entity.transaction.TransactionFactory;
042: import org.ofbiz.entity.transaction.TransactionUtil;
043: import org.ofbiz.security.Security;
044: import org.ofbiz.security.SecurityConfigurationException;
045: import org.ofbiz.security.SecurityFactory;
046: import org.ofbiz.service.config.ServiceConfigUtil;
047: import org.ofbiz.service.eca.ServiceEcaUtil;
048: import org.ofbiz.service.engine.GenericEngine;
049: import org.ofbiz.service.engine.GenericEngineFactory;
050: import org.ofbiz.service.group.ServiceGroupReader;
051: import org.ofbiz.service.jms.JmsListenerFactory;
052: import org.ofbiz.service.job.JobManager;
053:
054: /**
055: * Global Service Dispatcher
056: *
057: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
058: * @version $Revision: 1.15 $
059: * @since 2.0
060: */
061: public class ServiceDispatcher {
062:
063: public static final String module = ServiceDispatcher.class
064: .getName();
065:
066: protected static Map dispatchers = new HashMap();
067: protected GenericDelegator delegator = null;
068: protected GenericEngineFactory factory = null;
069: protected Security security = null;
070: protected Map localContext = null;
071: protected JobManager jm = null;
072: protected JmsListenerFactory jlf = null;
073:
074: public ServiceDispatcher(GenericDelegator delegator) {
075: Debug.logInfo("[ServiceDispatcher] : Creating new instance.",
076: module);
077: factory = new GenericEngineFactory(this );
078: ServiceGroupReader.readConfig();
079: ServiceEcaUtil.readConfig();
080:
081: this .delegator = delegator;
082: this .localContext = new HashMap();
083: if (delegator != null) {
084: try {
085: this .security = SecurityFactory.getInstance(delegator);
086: } catch (SecurityConfigurationException e) {
087: Debug
088: .logError(
089: e,
090: "[ServiceDispatcher.init] : No instance of security imeplemtation found.",
091: module);
092: }
093: }
094: this .jm = new JobManager(this .delegator);
095: this .jlf = new JmsListenerFactory(this );
096: }
097:
098: /**
099: * Returns a pre-registered instance of the ServiceDispatcher associated with this delegator.
100: * @param delegator the local delegator
101: * @return A reference to this global ServiceDispatcher
102: */
103: public static ServiceDispatcher getInstance(String name,
104: GenericDelegator delegator) {
105: ServiceDispatcher sd = getInstance(null, null, delegator);
106:
107: if (!sd.containsContext(name)) {
108: return null;
109: }
110: return sd;
111: }
112:
113: /**
114: * Returns an instance of the ServiceDispatcher associated with this delegator and registers the loader.
115: * @param name the local dispatcher
116: * @param context the context of the local dispatcher
117: * @param delegator the local delegator
118: * @return A reference to this global ServiceDispatcher
119: */
120: public static ServiceDispatcher getInstance(String name,
121: DispatchContext context, GenericDelegator delegator) {
122: ServiceDispatcher sd = null;
123:
124: String dispatcherKey = delegator != null ? delegator
125: .getDelegatorName() : "null";
126: sd = (ServiceDispatcher) dispatchers.get(dispatcherKey);
127: if (sd == null) {
128: synchronized (ServiceDispatcher.class) {
129: if (Debug.verboseOn())
130: Debug.logVerbose(
131: "[ServiceDispatcher.getInstance] : No instance found ("
132: + delegator.getDelegatorName()
133: + ").", module);
134: sd = (ServiceDispatcher) dispatchers.get(dispatcherKey);
135: if (sd == null) {
136: sd = new ServiceDispatcher(delegator);
137: dispatchers.put(dispatcherKey, sd);
138: }
139: }
140: }
141: if (name != null && context != null) {
142: sd.register(name, context);
143: }
144: return sd;
145: }
146:
147: /**
148: * Registers the loader with this ServiceDispatcher
149: * @param name the local dispatcher
150: * @param context the context of the local dispatcher
151: */
152: public void register(String name, DispatchContext context) {
153: if (Debug.infoOn())
154: Debug.logInfo(
155: "[ServiceDispatcher.register] : Registered dispatcher: "
156: + context.getName(), module);
157: this .localContext.put(name, context);
158: }
159:
160: /**
161: * De-Registers the loader with this ServiceDispatcher
162: * @param local the LocalDispatcher to de-register
163: */
164: public void deregister(LocalDispatcher local) {
165: if (Debug.infoOn())
166: Debug.logInfo(
167: "[ServiceDispatcher.deregister] : De-Registering dispatcher: "
168: + local.getName(), module);
169: localContext.remove(local.getName());
170: if (localContext.size() == 1) { // 1 == the JMSDispatcher
171: try {
172: this .shutdown();
173: } catch (GenericServiceException e) {
174: Debug.logError(e,
175: "Trouble shutting down ServiceDispatcher!",
176: module);
177: }
178: }
179: }
180:
181: /**
182: * Run the service synchronously and return the result.
183: * @param localName Name of the context to use.
184: * @param service Service model object.
185: * @param context Map of name, value pairs composing the context.
186: * @return Map of name, value pairs composing the result.
187: * @throws ServiceAuthException
188: * @throws ServiceValidationException
189: * @throws GenericServiceException
190: */
191: public Map runSync(String localName, ModelService service,
192: Map context) throws ServiceAuthException,
193: ServiceValidationException, GenericServiceException {
194: return runSync(localName, service, context, true);
195: }
196:
197: /**
198: * Run the service synchronously and IGNORE the result.
199: * @param localName Name of the context to use.
200: * @param service Service model object.
201: * @param context Map of name, value pairs composing the context.
202: * @throws ServiceAuthException
203: * @throws ServiceValidationException
204: * @throws GenericServiceException
205: */
206: public void runSyncIgnore(String localName, ModelService service,
207: Map context) throws ServiceAuthException,
208: ServiceValidationException, GenericServiceException {
209: runSync(localName, service, context, false);
210: }
211:
212: /**
213: * Run the service synchronously and return the result.
214: * @param localName Name of the context to use.
215: * @param modelService Service model object.
216: * @param context Map of name, value pairs composing the context.
217: * @param validateOut Validate OUT parameters
218: * @return Map of name, value pairs composing the result.
219: * @throws ServiceAuthException
220: * @throws ServiceValidationException
221: * @throws GenericServiceException
222: */
223: public Map runSync(String localName, ModelService modelService,
224: Map context, boolean validateOut)
225: throws ServiceAuthException, ServiceValidationException,
226: GenericServiceException {
227: boolean debugging = checkDebug(modelService, 1, true);
228: if (Debug.verboseOn()) {
229: Debug.logVerbose(
230: "[ServiceDispatcher.runSync] : invoking service "
231: + modelService.name + " ["
232: + modelService.location + "/"
233: + modelService.invoke + "] ("
234: + modelService.engineName + ")", module);
235: }
236:
237: // check the locale
238: this .checkLocale(context);
239:
240: // for isolated transactions
241: TransactionManager tm = TransactionFactory
242: .getTransactionManager();
243: Transaction parentTransaction = null;
244:
245: // start the transaction
246: boolean beganTrans = false;
247: if (modelService.useTransaction) {
248: try {
249: beganTrans = TransactionUtil
250: .begin(modelService.transactionTimeout);
251: } catch (GenericTransactionException te) {
252: throw new GenericServiceException(
253: "Cannot start the transaction.", te.getNested());
254: }
255:
256: // isolate the transaction if defined
257: if (modelService.requireNewTransaction && !beganTrans) {
258: try {
259: parentTransaction = tm.suspend();
260: } catch (SystemException se) {
261: Debug.logError(se,
262: "Problems suspending current transaction",
263: module);
264: throw new GenericServiceException(
265: "Problems suspending transaction, see logs");
266: }
267:
268: // now start a new transaction
269: try {
270: beganTrans = TransactionUtil
271: .begin(modelService.transactionTimeout);
272: } catch (GenericTransactionException gte) {
273: throw new GenericServiceException(
274: "Cannot start the transaction.", gte
275: .getNested());
276: }
277: }
278: }
279:
280: // needed for events
281: DispatchContext ctx = (DispatchContext) localContext
282: .get(localName);
283:
284: try {
285: // get eventMap once for all calls for speed, don't do event calls if it is null
286: Map eventMap = ServiceEcaUtil
287: .getServiceEventMap(modelService.name);
288:
289: // setup global transaction ECA listeners
290: if (eventMap != null)
291: ServiceEcaUtil.evalRules(modelService.name, eventMap,
292: "global-rollback", ctx, context, null, false);
293: if (eventMap != null)
294: ServiceEcaUtil.evalRules(modelService.name, eventMap,
295: "global-commit", ctx, context, null, false);
296:
297: // pre-auth ECA
298: if (eventMap != null)
299: ServiceEcaUtil.evalRules(modelService.name, eventMap,
300: "auth", ctx, context, null, false);
301:
302: context = checkAuth(localName, context, modelService);
303: Object userLogin = context.get("userLogin");
304:
305: if (modelService.auth && userLogin == null) {
306: throw new ServiceAuthException(
307: "User authorization is required for this service: "
308: + modelService.name
309: + modelService.debugInfo());
310: }
311:
312: // setup the engine
313: GenericEngine engine = getGenericEngine(modelService.engineName);
314:
315: // pre-validate ECA
316: if (eventMap != null)
317: ServiceEcaUtil.evalRules(modelService.name, eventMap,
318: "in-validate", ctx, context, null, false);
319:
320: // validate the context
321: if (modelService.validate) {
322: try {
323: modelService.validate(context,
324: ModelService.IN_PARAM);
325: } catch (ServiceValidationException e) {
326: Debug.logError(e, "Incoming context (in runSync : "
327: + modelService.name
328: + ") does not match expected requirements",
329: module);
330: throw e;
331: }
332: }
333:
334: // pre-invoke ECA
335: if (eventMap != null)
336: ServiceEcaUtil.evalRules(modelService.name, eventMap,
337: "invoke", ctx, context, null, false);
338:
339: // ===== invoke the service =====
340: Map result = engine.runSync(localName, modelService,
341: context);
342:
343: // if anything but the error response, is not an error
344: boolean isError = ModelService.RESPOND_ERROR.equals(result
345: .get(ModelService.RESPONSE_MESSAGE));
346:
347: // create a new context with the results to pass to ECA services; necessary because caller may reuse this context
348: Map ecaContext = new HashMap(context);
349:
350: // copy all results: don't worry parameters that aren't allowed won't be passed to the ECA services
351: ecaContext.putAll(result);
352:
353: // validate the result
354: if (modelService.validate && validateOut) {
355: // pre-out-validate ECA
356: if (eventMap != null)
357: ServiceEcaUtil.evalRules(modelService.name,
358: eventMap, "out-validate", ctx, ecaContext,
359: result, isError);
360: try {
361: modelService.validate(result,
362: ModelService.OUT_PARAM);
363: } catch (ServiceValidationException e) {
364: Debug.logError(e, "Outgoing result (in runSync : "
365: + modelService.name
366: + ") does not match expected requirements",
367: module);
368: throw e;
369: }
370: }
371:
372: // pre-commit ECA
373: if (eventMap != null)
374: ServiceEcaUtil.evalRules(modelService.name, eventMap,
375: "commit", ctx, ecaContext, result, isError);
376:
377: // if there was an error, rollback transaction, otherwise commit
378: if (isError) {
379: // try to log the error
380: Debug.logError("Service Error [" + modelService.name
381: + "]: "
382: + result.get(ModelService.ERROR_MESSAGE),
383: module);
384:
385: // rollback the transaction
386: try {
387: TransactionUtil.rollback(beganTrans);
388: } catch (GenericTransactionException e) {
389: Debug.logError(e, "Could not rollback transaction",
390: module);
391: }
392: } else {
393: // commit the transaction
394: try {
395: TransactionUtil.commit(beganTrans);
396: } catch (GenericTransactionException e) {
397: Debug.logError(e, "Could not commit transaction",
398: module);
399: throw new GenericServiceException(
400: "Commit transaction failed");
401: }
402: }
403:
404: // resume the parent transaction
405: if (parentTransaction != null) {
406: try {
407: tm.resume(parentTransaction);
408: } catch (InvalidTransactionException ite) {
409: Debug.logWarning(ite,
410: "Invalid transaction, not resumed", module);
411: } catch (IllegalStateException ise) {
412: Debug.logError(ise,
413: "Trouble resuming parent transaction",
414: module);
415: throw new GenericServiceException(
416: "Resume transaction exception, see logs");
417: } catch (SystemException se) {
418: Debug.logError(se,
419: "Trouble resuming parent transaction",
420: module);
421: throw new GenericServiceException(
422: "Resume transaction exception, see logs");
423: }
424: }
425:
426: // pre-return ECA
427: if (eventMap != null)
428: ServiceEcaUtil.evalRules(modelService.name, eventMap,
429: "return", ctx, ecaContext, result, isError);
430:
431: checkDebug(modelService, 0, debugging);
432: return result;
433: } catch (Throwable t) {
434: Debug.logError(t, "Service [" + modelService.name
435: + "] threw an unexpected exception/error", module);
436: try {
437: TransactionUtil.rollback(beganTrans);
438: } catch (GenericTransactionException te) {
439: Debug.logError(te, "Cannot rollback transaction",
440: module);
441: }
442: checkDebug(modelService, 0, debugging);
443: if (t instanceof ServiceAuthException) {
444: throw (ServiceAuthException) t;
445: } else if (t instanceof ServiceValidationException) {
446: throw (ServiceValidationException) t;
447: } else if (t instanceof GenericServiceException) {
448: throw (GenericServiceException) t;
449: } else {
450: throw new GenericServiceException("Service ["
451: + modelService.name + "] Failed"
452: + modelService.debugInfo(), t);
453: }
454: }
455: }
456:
457: /**
458: * Run the service asynchronously, passing an instance of GenericRequester that will receive the result.
459: * @param localName Name of the context to use.
460: * @param service Service model object.
461: * @param context Map of name, value pairs composing the context.
462: * @param requester Object implementing GenericRequester interface which will receive the result.
463: * @param persist True for store/run; False for run.
464: * @throws ServiceAuthException
465: * @throws ServiceValidationException
466: * @throws GenericServiceException
467: */
468: public void runAsync(String localName, ModelService service,
469: Map context, GenericRequester requester, boolean persist)
470: throws ServiceAuthException, ServiceValidationException,
471: GenericServiceException {
472: boolean debugging = checkDebug(service, 1, true);
473: if (Debug.verboseOn()) {
474: Debug.logVerbose(
475: "[ServiceDispatcher.runAsync] : prepareing service "
476: + service.name + " [" + service.location
477: + "/" + service.invoke + "] ("
478: + service.engineName + ")", module);
479: }
480:
481: // check the locale
482: this .checkLocale(context);
483:
484: // for isolated transactions
485: TransactionManager tm = TransactionFactory
486: .getTransactionManager();
487: Transaction parentTransaction = null;
488:
489: // start the transaction
490: boolean beganTrans = false;
491: if (service.useTransaction) {
492: try {
493: beganTrans = TransactionUtil
494: .begin(service.transactionTimeout);
495: } catch (GenericTransactionException te) {
496: throw new GenericServiceException(
497: "Cannot start the transaction.", te.getNested());
498: }
499:
500: // isolate the transaction if defined
501: if (service.requireNewTransaction && !beganTrans) {
502: try {
503: parentTransaction = tm.suspend();
504: } catch (SystemException se) {
505: Debug.logError(se,
506: "Problems suspending current transaction",
507: module);
508: throw new GenericServiceException(
509: "Problems suspending transaction, see logs");
510: }
511:
512: // now start a new transaction
513: try {
514: beganTrans = TransactionUtil
515: .begin(service.transactionTimeout);
516: } catch (GenericTransactionException gte) {
517: throw new GenericServiceException(
518: "Cannot start the transaction.", gte
519: .getNested());
520: }
521: }
522: }
523:
524: // needed for events
525: DispatchContext ctx = (DispatchContext) localContext
526: .get(localName);
527:
528: try {
529: // get eventMap once for all calls for speed, don't do event calls if it is null
530: Map eventMap = ServiceEcaUtil
531: .getServiceEventMap(service.name);
532:
533: // pre-auth ECA
534: if (eventMap != null)
535: ServiceEcaUtil.evalRules(service.name, eventMap,
536: "auth", ctx, context, null, false);
537:
538: context = checkAuth(localName, context, service);
539: Object userLogin = context.get("userLogin");
540:
541: if (service.auth && userLogin == null)
542: throw new ServiceAuthException(
543: "User authorization is required for this service: "
544: + service.name + service.debugInfo());
545:
546: // setup the engine
547: GenericEngine engine = getGenericEngine(service.engineName);
548:
549: // pre-validate ECA
550: if (eventMap != null)
551: ServiceEcaUtil.evalRules(service.name, eventMap,
552: "in-validate", ctx, context, null, false);
553:
554: // validate the context
555: if (service.validate) {
556: try {
557: service.validate(context, ModelService.IN_PARAM);
558: } catch (ServiceValidationException e) {
559: Debug
560: .logError(
561: e,
562: "Incoming service context (in runAsync: "
563: + service.name
564: + ") does not match expected requirements",
565: module);
566: throw e;
567: }
568: }
569:
570: // run the service
571: if (requester != null) {
572: engine.runAsync(localName, service, context, requester,
573: persist);
574: } else {
575: engine.runAsync(localName, service, context, persist);
576: }
577:
578: // always try to commit the transaction since we don't know in this case if its was an error or not
579: try {
580: TransactionUtil.commit(beganTrans);
581: } catch (GenericTransactionException e) {
582: Debug.logError(e, "Could not commit transaction",
583: module);
584: throw new GenericServiceException(
585: "Commit transaction failed");
586: }
587:
588: // resume the parent transaction
589: if (parentTransaction != null) {
590: try {
591: tm.resume(parentTransaction);
592: } catch (InvalidTransactionException ite) {
593: Debug.logWarning(ite,
594: "Invalid transaction, not resumed", module);
595: } catch (IllegalStateException ise) {
596: Debug.logError(ise,
597: "Trouble resuming parent transaction",
598: module);
599: throw new GenericServiceException(
600: "Resume transaction exception, see logs");
601: } catch (SystemException se) {
602: Debug.logError(se,
603: "Trouble resuming parent transaction",
604: module);
605: throw new GenericServiceException(
606: "Resume transaction exception, see logs");
607: }
608: }
609:
610: checkDebug(service, 0, debugging);
611: } catch (Throwable t) {
612: Debug.logError(t, "Service [" + service.name
613: + "] threw an unexpected exception/error", module);
614: try {
615: TransactionUtil.rollback(beganTrans);
616: } catch (GenericTransactionException te) {
617: Debug.logError(te, "Cannot rollback transaction",
618: module);
619: }
620: checkDebug(service, 0, debugging);
621: if (t instanceof ServiceAuthException) {
622: throw (ServiceAuthException) t;
623: } else if (t instanceof ServiceValidationException) {
624: throw (ServiceValidationException) t;
625: } else if (t instanceof GenericServiceException) {
626: throw (GenericServiceException) t;
627: } else {
628: throw new GenericServiceException("Service ["
629: + service.name + "] Failed"
630: + service.debugInfo(), t);
631: }
632: }
633: }
634:
635: /**
636: * Run the service asynchronously and IGNORE the result.
637: * @param localName Name of the context to use.
638: * @param service Service model object.
639: * @param context Map of name, value pairs composing the context.
640: * @param persist True for store/run; False for run.
641: * @throws ServiceAuthException
642: * @throws ServiceValidationException
643: * @throws GenericServiceException
644: */
645: public void runAsync(String localName, ModelService service,
646: Map context, boolean persist) throws ServiceAuthException,
647: ServiceValidationException, GenericServiceException {
648: this .runAsync(localName, service, context, null, persist);
649: }
650:
651: /**
652: * Gets the GenericEngine instance that corresponds to the given name
653: * @param engineName Name of the engine
654: * @return GenericEngine instance that corresponds to the engineName
655: */
656: public GenericEngine getGenericEngine(String engineName)
657: throws GenericServiceException {
658: return factory.getGenericEngine(engineName);
659: }
660:
661: /**
662: * Gets the JobManager associated with this dispatcher
663: * @return JobManager that is associated with this dispatcher
664: */
665: public JobManager getJobManager() {
666: return this .jm;
667: }
668:
669: /**
670: * Gets the JmsListenerFactory which holds the message listeners.
671: * @return JmsListenerFactory
672: */
673: public JmsListenerFactory getJMSListenerFactory() {
674: return this .jlf;
675: }
676:
677: /**
678: * Gets the GenericDelegator associated with this dispatcher
679: * @return GenericDelegator associated with this dispatcher
680: */
681: public GenericDelegator getDelegator() {
682: return this .delegator;
683: }
684:
685: /**
686: * Gets the Security object associated with this dispatcher
687: * @return Security object associated with this dispatcher
688: */
689: public Security getSecurity() {
690: return this .security;
691: }
692:
693: /**
694: * Gets the local context from a name
695: * @param name of the context to find.
696: */
697: public DispatchContext getLocalContext(String name) {
698: return (DispatchContext) localContext.get(name);
699: }
700:
701: /**
702: * Gets the local dispatcher from a name
703: * @param name of the LocalDispatcher to find.
704: * @return LocalDispatcher matching the loader name
705: */
706: public LocalDispatcher getLocalDispatcher(String name) {
707: return ((DispatchContext) localContext.get(name))
708: .getDispatcher();
709: }
710:
711: /**
712: * Test if this dispatcher instance contains the local context.
713: * @param name of the local context
714: * @return true if the local context is found in this dispatcher.
715: */
716: public boolean containsContext(String name) {
717: return localContext.containsKey(name);
718: }
719:
720: protected void shutdown() throws GenericServiceException {
721: Debug.logImportant("Shutting down the service engine...",
722: module);
723: // shutdown JMS listeners
724: jlf.closeListeners();
725: // shutdown the job scheduler
726: jm.finalize();
727: }
728:
729: // checks if parameters were passed for authentication
730: private Map checkAuth(String localName, Map context,
731: ModelService origService) throws ServiceAuthException,
732: GenericServiceException {
733: String service = ServiceConfigUtil.getElementAttr(
734: "authorization", "service-name");
735:
736: if (service == null) {
737: throw new GenericServiceException(
738: "No Authentication Service Defined");
739: }
740: if (service.equals(origService.name)) {
741: // manually calling the auth service, don't continue...
742: return context;
743: }
744:
745: if (context.containsKey("login.username")) {
746: // check for a username/password, if there log the user in and make the userLogin object
747: String username = (String) context.get("login.username");
748:
749: if (context.containsKey("login.password")) {
750: String password = (String) context
751: .get("login.password");
752:
753: context.put("userLogin", getLoginObject(service,
754: localName, username, password));
755: context.remove("login.password");
756: } else {
757: context.put("userLogin", getLoginObject(service,
758: localName, username, null));
759: }
760: context.remove("login.username");
761: } else {
762: // if a userLogin object is there, make sure the given username/password exists in our local database
763: GenericValue userLogin = (GenericValue) context
764: .get("userLogin");
765:
766: if (userLogin != null) {
767: GenericValue newUserLogin = getLoginObject(service,
768: localName, userLogin.getString("userLoginId"),
769: userLogin.getString("currentPassword"));
770:
771: if (newUserLogin == null) {
772: // uh oh, couldn't validate that one...
773: // we'll have to remove it from the incoming context which will cause an auth error later if auth is required
774: context.remove("userLogin");
775: }
776: }
777: }
778:
779: // evaluate permissions for the service or throw exception if fail.
780: DispatchContext dctx = this .getLocalContext(localName);
781: GenericValue userLogin = (GenericValue) context
782: .get("userLogin");
783: if (!origService.evalPermissions(dctx.getSecurity(), userLogin)) {
784: throw new ServiceAuthException(
785: "You do not have permission to invoke this service");
786: }
787:
788: return context;
789: }
790:
791: // gets a value object from name/password pair
792: private GenericValue getLoginObject(String service,
793: String localName, String username, String password)
794: throws GenericServiceException {
795: Map context = UtilMisc.toMap("login.username", username,
796: "login.password", password, "isServiceAuth",
797: new Boolean(true));
798:
799: if (Debug.verboseOn())
800: Debug
801: .logVerbose(
802: "[ServiceDispathcer.authenticate] : Invoking UserLogin Service",
803: module);
804:
805: // get the dispatch context and service model
806: DispatchContext dctx = getLocalContext(localName);
807: ModelService model = dctx.getModelService(service);
808:
809: // get the service engine
810: GenericEngine engine = getGenericEngine(model.engineName);
811:
812: // invoke the service and get the UserLogin value object
813: Map result = engine.runSync(localName, model, context);
814: GenericValue value = (GenericValue) result.get("userLogin");
815:
816: return value;
817: }
818:
819: // checks the locale object in the context
820: private void checkLocale(Map context) {
821: Object locale = context.get("locale");
822: Locale newLocale = null;
823:
824: if (locale != null) {
825: if (locale instanceof Locale) {
826: return;
827: } else if (locale instanceof String) {
828: // en_US = lang_COUNTRY
829: newLocale = UtilMisc.parseLocale((String) locale);
830: }
831: }
832:
833: if (newLocale == null) {
834: newLocale = Locale.getDefault();
835: }
836: context.put("locale", newLocale);
837: }
838:
839: // mode 1 = beginning (turn on) mode 0 = end (turn off)
840: private boolean checkDebug(ModelService model, int mode,
841: boolean enable) {
842: boolean debugOn = Debug.verboseOn();
843: switch (mode) {
844: case 0:
845: if (model.debug && enable && debugOn) {
846: // turn it off
847: Debug.set(Debug.VERBOSE, false);
848: Debug.logInfo("Verbose logging turned OFF", module);
849: return true;
850: }
851: break;
852: case 1:
853: if (model.debug && enable && !debugOn) {
854: // turn it on
855: Debug.set(Debug.VERBOSE, true);
856: Debug.logInfo("Verbose logging turned ON", module);
857: return true;
858: }
859: break;
860: default:
861: Debug.logError(
862: "Invalid mode for checkDebug should be (0 or 1)",
863: module);
864: }
865: return false;
866: }
867: }
|