Source Code Cross Referenced for ServiceDispatcher.java in  » ERP-CRM-Financial » ofbiz » org » ofbiz » service » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » ofbiz » org.ofbiz.service 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Licensed to the Apache Software Foundation (ASF) under one
0003:         * or more contributor license agreements.  See the NOTICE file
0004:         * distributed with this work for additional information
0005:         * regarding copyright ownership.  The ASF licenses this file
0006:         * to you under the Apache License, Version 2.0 (the
0007:         * "License"); you may not use this file except in compliance
0008:         * with the License.  You may obtain a copy of the License at
0009:         * 
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         * 
0012:         * Unless required by applicable law or agreed to in writing,
0013:         * software distributed under the License is distributed on an
0014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015:         * KIND, either express or implied.  See the License for the
0016:         * specific language governing permissions and limitations
0017:         * under the License.
0018:         *******************************************************************************/package org.ofbiz.service;
0019:
0020:        import java.util.Iterator;
0021:        import java.util.List;
0022:        import java.util.Locale;
0023:        import java.util.Map;
0024:        import javax.transaction.Transaction;
0025:
0026:        import javolution.util.FastList;
0027:        import javolution.util.FastMap;
0028:        import org.apache.commons.collections.map.LRUMap;
0029:        import org.w3c.dom.Element;
0030:
0031:        import org.ofbiz.base.config.GenericConfigException;
0032:        import org.ofbiz.base.util.Debug;
0033:        import org.ofbiz.base.util.UtilMisc;
0034:        import org.ofbiz.base.util.UtilTimer;
0035:        import org.ofbiz.base.util.UtilValidate;
0036:        import org.ofbiz.base.util.UtilXml;
0037:        import org.ofbiz.base.util.GeneralRuntimeException;
0038:        import org.ofbiz.entity.GenericDelegator;
0039:        import org.ofbiz.entity.GenericEntityException;
0040:        import org.ofbiz.entity.GenericValue;
0041:        import org.ofbiz.entity.transaction.DebugXaResource;
0042:        import org.ofbiz.entity.transaction.GenericTransactionException;
0043:        import org.ofbiz.entity.transaction.TransactionUtil;
0044:        import org.ofbiz.security.Security;
0045:        import org.ofbiz.security.SecurityConfigurationException;
0046:        import org.ofbiz.security.SecurityFactory;
0047:        import org.ofbiz.service.config.ServiceConfigUtil;
0048:        import org.ofbiz.service.eca.ServiceEcaUtil;
0049:        import org.ofbiz.service.engine.GenericEngine;
0050:        import org.ofbiz.service.engine.GenericEngineFactory;
0051:        import org.ofbiz.service.group.ServiceGroupReader;
0052:        import org.ofbiz.service.jms.JmsListenerFactory;
0053:        import org.ofbiz.service.job.JobManager;
0054:        import org.ofbiz.service.job.JobManagerException;
0055:
0056:        /**
0057:         * Global Service Dispatcher
0058:         */
0059:        public class ServiceDispatcher {
0060:
0061:            public static final String module = ServiceDispatcher.class
0062:                    .getName();
0063:            public static final int lruLogSize = 200;
0064:
0065:            protected static Map runLog = new LRUMap(lruLogSize);
0066:            protected static Map dispatchers = FastMap.newInstance();
0067:            protected static boolean enableJM = true;
0068:            protected static boolean enableJMS = true;
0069:            protected static boolean enableSvcs = true;
0070:
0071:            protected GenericDelegator delegator = null;
0072:            protected GenericEngineFactory factory = null;
0073:            protected Security security = null;
0074:            protected Map localContext = null;
0075:            protected Map callbacks = null;
0076:            protected JobManager jm = null;
0077:            protected JmsListenerFactory jlf = null;
0078:
0079:            public ServiceDispatcher(GenericDelegator delegator,
0080:                    boolean enableJM, boolean enableJMS, boolean enableSvcs) {
0081:                Debug.logInfo("[ServiceDispatcher] : Creating new instance.",
0082:                        module);
0083:                factory = new GenericEngineFactory(this );
0084:                ServiceGroupReader.readConfig();
0085:                ServiceEcaUtil.readConfig();
0086:
0087:                this .delegator = delegator;
0088:                this .localContext = FastMap.newInstance();
0089:                this .callbacks = FastMap.newInstance();
0090:
0091:                if (delegator != null) {
0092:                    try {
0093:                        this .security = SecurityFactory.getInstance(delegator);
0094:                    } catch (SecurityConfigurationException e) {
0095:                        Debug
0096:                                .logError(
0097:                                        e,
0098:                                        "[ServiceDispatcher.init] : No instance of security imeplemtation found.",
0099:                                        module);
0100:                    }
0101:                }
0102:
0103:                // make sure we haven't disabled these features from running
0104:                if (enableJM) {
0105:                    try {
0106:                        this .jm = new JobManager(this .delegator);
0107:                    } catch (GeneralRuntimeException e) {
0108:                        Debug.logWarning(e.getMessage(), module);
0109:                    }
0110:                }
0111:
0112:                if (enableJMS) {
0113:                    this .jlf = new JmsListenerFactory(this );
0114:                }
0115:
0116:                if (enableSvcs) {
0117:                    this .runStartupServices();
0118:                }
0119:            }
0120:
0121:            public ServiceDispatcher(GenericDelegator delegator) {
0122:                this (delegator, enableJM, enableJMS, enableSvcs);
0123:            }
0124:
0125:            /**
0126:             * Returns a pre-registered instance of the ServiceDispatcher associated with this delegator.
0127:             * @param delegator the local delegator
0128:             * @return A reference to this global ServiceDispatcher
0129:             */
0130:            public static ServiceDispatcher getInstance(String name,
0131:                    GenericDelegator delegator) {
0132:                ServiceDispatcher sd = getInstance(null, null, delegator);
0133:
0134:                if (!sd.containsContext(name)) {
0135:                    return null;
0136:                }
0137:                return sd;
0138:            }
0139:
0140:            /**
0141:             * Returns an instance of the ServiceDispatcher associated with this delegator and registers the loader.
0142:             * @param name the local dispatcher
0143:             * @param context the context of the local dispatcher
0144:             * @param delegator the local delegator
0145:             * @return A reference to this global ServiceDispatcher
0146:             */
0147:            public static ServiceDispatcher getInstance(String name,
0148:                    DispatchContext context, GenericDelegator delegator) {
0149:                ServiceDispatcher sd;
0150:
0151:                String dispatcherKey = delegator != null ? delegator
0152:                        .getDelegatorName() : "null";
0153:                sd = (ServiceDispatcher) dispatchers.get(dispatcherKey);
0154:                if (sd == null) {
0155:                    synchronized (ServiceDispatcher.class) {
0156:                        if (Debug.verboseOn())
0157:                            Debug.logVerbose(
0158:                                    "[ServiceDispatcher.getInstance] : No instance found ("
0159:                                            + dispatcherKey + ").", module);
0160:                        sd = (ServiceDispatcher) dispatchers.get(dispatcherKey);
0161:                        if (sd == null) {
0162:                            sd = new ServiceDispatcher(delegator);
0163:                            dispatchers.put(dispatcherKey, sd);
0164:                        }
0165:                    }
0166:                }
0167:                if (name != null && context != null) {
0168:                    sd.register(name, context);
0169:                }
0170:                return sd;
0171:            }
0172:
0173:            /**
0174:             * Registers the loader with this ServiceDispatcher
0175:             * @param name the local dispatcher
0176:             * @param context the context of the local dispatcher
0177:             */
0178:            public void register(String name, DispatchContext context) {
0179:                if (Debug.infoOn())
0180:                    Debug.logInfo(
0181:                            "Registered dispatcher: " + context.getName(),
0182:                            module);
0183:                this .localContext.put(name, context);
0184:            }
0185:
0186:            /**
0187:             * De-Registers the loader with this ServiceDispatcher
0188:             * @param local the LocalDispatcher to de-register
0189:             */
0190:            public void deregister(LocalDispatcher local) {
0191:                if (Debug.infoOn())
0192:                    Debug.logInfo("De-Registering dispatcher: "
0193:                            + local.getName(), module);
0194:                localContext.remove(local.getName());
0195:                if (localContext.size() == 1) { // 1 == the JMSDispatcher
0196:                    try {
0197:                        this .shutdown();
0198:                    } catch (GenericServiceException e) {
0199:                        Debug.logError(e,
0200:                                "Trouble shutting down ServiceDispatcher!",
0201:                                module);
0202:                    }
0203:                }
0204:            }
0205:
0206:            public synchronized void registerCallback(String serviceName,
0207:                    GenericServiceCallback cb) {
0208:                List callBackList = (List) callbacks.get(serviceName);
0209:                if (callBackList == null) {
0210:                    callBackList = FastList.newInstance();
0211:                }
0212:                callBackList.add(cb);
0213:                callbacks.put(serviceName, callBackList);
0214:            }
0215:
0216:            public List getCallbacks(String serviceName) {
0217:                return (List) callbacks.get(serviceName);
0218:            }
0219:
0220:            /**
0221:             * Run the service synchronously and return the result.
0222:             * @param localName Name of the context to use.
0223:             * @param service Service model object.
0224:             * @param context Map of name, value pairs composing the context.
0225:             * @return Map of name, value pairs composing the result.
0226:             * @throws ServiceAuthException
0227:             * @throws ServiceValidationException
0228:             * @throws GenericServiceException
0229:             */
0230:            public Map runSync(String localName, ModelService service,
0231:                    Map context) throws ServiceAuthException,
0232:                    ServiceValidationException, GenericServiceException {
0233:                return runSync(localName, service, context, true);
0234:            }
0235:
0236:            /**
0237:             * Run the service synchronously and IGNORE the result.
0238:             * @param localName Name of the context to use.
0239:             * @param service Service model object.
0240:             * @param context Map of name, value pairs composing the context.
0241:             * @throws ServiceAuthException
0242:             * @throws ServiceValidationException
0243:             * @throws GenericServiceException
0244:             */
0245:            public void runSyncIgnore(String localName, ModelService service,
0246:                    Map context) throws ServiceAuthException,
0247:                    ServiceValidationException, GenericServiceException {
0248:                runSync(localName, service, context, false);
0249:            }
0250:
0251:            /**
0252:             * Run the service synchronously and return the result.
0253:             * @param localName Name of the context to use.
0254:             * @param modelService Service model object.
0255:             * @param context Map of name, value pairs composing the context.
0256:             * @param validateOut Validate OUT parameters
0257:             * @return Map of name, value pairs composing the result.
0258:             * @throws ServiceAuthException
0259:             * @throws ServiceValidationException
0260:             * @throws GenericServiceException
0261:             */
0262:            public Map runSync(String localName, ModelService modelService,
0263:                    Map context, boolean validateOut)
0264:                    throws ServiceAuthException, ServiceValidationException,
0265:                    GenericServiceException {
0266:                long serviceStartTime = System.currentTimeMillis();
0267:                boolean debugging = checkDebug(modelService, 1, true);
0268:                if (Debug.verboseOn()) {
0269:                    Debug.logVerbose(
0270:                            "[ServiceDispatcher.runSync] : invoking service "
0271:                                    + modelService.name + " ["
0272:                                    + modelService.location + "/"
0273:                                    + modelService.invoke + "] ("
0274:                                    + modelService.engineName + ")", module);
0275:                }
0276:
0277:                if (context == null) {
0278:                    context = FastMap.newInstance();
0279:                }
0280:
0281:                // setup the result map
0282:                Map result = FastMap.newInstance();
0283:                boolean isFailure = false;
0284:                boolean isError = false;
0285:
0286:                // set up the running service log
0287:                RunningService rs = this .logService(localName, modelService,
0288:                        GenericEngine.SYNC_MODE);
0289:
0290:                // get eventMap once for all calls for speed, don't do event calls if it is null
0291:                Map eventMap = ServiceEcaUtil
0292:                        .getServiceEventMap(modelService.name);
0293:
0294:                // check the locale
0295:                Locale locale = this .checkLocale(context);
0296:
0297:                // setup the engine and context
0298:                DispatchContext ctx = (DispatchContext) localContext
0299:                        .get(localName);
0300:                GenericEngine engine = this 
0301:                        .getGenericEngine(modelService.engineName);
0302:
0303:                // setup default IN values
0304:                modelService
0305:                        .updateDefaultValues(context, ModelService.IN_PARAM);
0306:
0307:                Map ecaContext = null;
0308:
0309:                // for isolated transactions
0310:                Transaction parentTransaction = null;
0311:
0312:                // start the transaction
0313:                boolean beganTrans = false;
0314:                try {
0315:                    if (modelService.useTransaction) {
0316:                        beganTrans = TransactionUtil
0317:                                .begin(modelService.transactionTimeout);
0318:                        // isolate the transaction if defined
0319:                        if (modelService.requireNewTransaction && !beganTrans) {
0320:                            parentTransaction = TransactionUtil.suspend();
0321:                            // now start a new transaction
0322:                            beganTrans = TransactionUtil
0323:                                    .begin(modelService.transactionTimeout);
0324:                        }
0325:                    }
0326:
0327:                    // XAResource debugging
0328:                    if (beganTrans && TransactionUtil.debugResources) {
0329:                        DebugXaResource dxa = new DebugXaResource(
0330:                                modelService.name);
0331:                        try {
0332:                            dxa.enlist();
0333:                        } catch (Exception e) {
0334:                            Debug.logError(e, module);
0335:                        }
0336:                    }
0337:
0338:                    try {
0339:                        // setup global transaction ECA listeners to execute later
0340:                        if (eventMap != null)
0341:                            ServiceEcaUtil.evalRules(modelService.name,
0342:                                    eventMap, "global-rollback", ctx, context,
0343:                                    result, isError, isFailure);
0344:                        if (eventMap != null)
0345:                            ServiceEcaUtil.evalRules(modelService.name,
0346:                                    eventMap, "global-commit", ctx, context,
0347:                                    result, isError, isFailure);
0348:
0349:                        // pre-auth ECA
0350:                        if (eventMap != null)
0351:                            ServiceEcaUtil.evalRules(modelService.name,
0352:                                    eventMap, "auth", ctx, context, result,
0353:                                    isError, isFailure);
0354:
0355:                        // check for pre-auth failure/errors
0356:                        isFailure = ServiceUtil.isFailure(result);
0357:                        isError = ServiceUtil.isError(result);
0358:
0359:                        context = checkAuth(localName, context, modelService);
0360:                        Object userLogin = context.get("userLogin");
0361:
0362:                        if (modelService.auth && userLogin == null) {
0363:                            throw new ServiceAuthException(
0364:                                    "User authorization is required for this service: "
0365:                                            + modelService.name
0366:                                            + modelService.debugInfo());
0367:                        }
0368:
0369:                        // pre-validate ECA
0370:                        if (eventMap != null)
0371:                            ServiceEcaUtil.evalRules(modelService.name,
0372:                                    eventMap, "in-validate", ctx, context,
0373:                                    result, isError, isFailure);
0374:
0375:                        // check for pre-validate failure/errors
0376:                        isFailure = ServiceUtil.isFailure(result);
0377:                        isError = ServiceUtil.isError(result);
0378:
0379:                        // validate the context
0380:                        if (modelService.validate && !isError && !isFailure) {
0381:                            try {
0382:                                modelService.validate(context,
0383:                                        ModelService.IN_PARAM, locale);
0384:                            } catch (ServiceValidationException e) {
0385:                                Debug
0386:                                        .logError(
0387:                                                e,
0388:                                                "Incoming context (in runSync : "
0389:                                                        + modelService.name
0390:                                                        + ") does not match expected requirements",
0391:                                                module);
0392:                                throw e;
0393:                            }
0394:                        }
0395:
0396:                        // pre-invoke ECA
0397:                        if (eventMap != null)
0398:                            ServiceEcaUtil.evalRules(modelService.name,
0399:                                    eventMap, "invoke", ctx, context, result,
0400:                                    isError, isFailure);
0401:
0402:                        // check for pre-invoke failure/errors
0403:                        isFailure = ServiceUtil.isFailure(result);
0404:                        isError = ServiceUtil.isError(result);
0405:
0406:                        // ===== invoke the service =====
0407:                        if (!isError && !isFailure) {
0408:                            Map invokeResult = engine.runSync(localName,
0409:                                    modelService, context);
0410:                            engine.sendCallbacks(modelService, context,
0411:                                    invokeResult, GenericEngine.SYNC_MODE);
0412:                            if (invokeResult != null) {
0413:                                result.putAll(invokeResult);
0414:                            } else {
0415:                                Debug.logWarning("Service (in runSync : "
0416:                                        + modelService.name
0417:                                        + ") returns null result", module);
0418:                            }
0419:                        }
0420:
0421:                        // re-check the errors/failures
0422:                        isFailure = ServiceUtil.isFailure(result);
0423:                        isError = ServiceUtil.isError(result);
0424:
0425:                        // create a new context with the results to pass to ECA services; necessary because caller may reuse this context
0426:                        ecaContext = FastMap.newInstance();
0427:                        ecaContext.putAll(context);
0428:
0429:                        // copy all results: don't worry parameters that aren't allowed won't be passed to the ECA services
0430:                        ecaContext.putAll(result);
0431:
0432:                        // setup default OUT values
0433:                        modelService.updateDefaultValues(context,
0434:                                ModelService.OUT_PARAM);
0435:
0436:                        // validate the result
0437:                        if (modelService.validate && validateOut) {
0438:                            // pre-out-validate ECA
0439:                            if (eventMap != null)
0440:                                ServiceEcaUtil.evalRules(modelService.name,
0441:                                        eventMap, "out-validate", ctx,
0442:                                        ecaContext, result, isError, isFailure);
0443:                            try {
0444:                                modelService.validate(result,
0445:                                        ModelService.OUT_PARAM, locale);
0446:                            } catch (ServiceValidationException e) {
0447:                                Debug
0448:                                        .logError(
0449:                                                e,
0450:                                                "Outgoing result (in runSync : "
0451:                                                        + modelService.name
0452:                                                        + ") does not match expected requirements",
0453:                                                module);
0454:                                throw e;
0455:                            }
0456:                        }
0457:
0458:                        // pre-commit ECA
0459:                        if (eventMap != null)
0460:                            ServiceEcaUtil.evalRules(modelService.name,
0461:                                    eventMap, "commit", ctx, ecaContext,
0462:                                    result, isError, isFailure);
0463:
0464:                        // check for pre-commit failure/errors
0465:                        isFailure = ServiceUtil.isFailure(result);
0466:                        isError = ServiceUtil.isError(result);
0467:
0468:                        // check for failure and log on info level; this is used for debugging
0469:                        if (isFailure) {
0470:                            Debug.logWarning("Service Failure ["
0471:                                    + modelService.name + "]: "
0472:                                    + ServiceUtil.getErrorMessage(result),
0473:                                    module);
0474:                        }
0475:
0476:                    } catch (Throwable t) {
0477:                        if (Debug.timingOn()) {
0478:                            UtilTimer.closeTimer(localName + " / "
0479:                                    + modelService.name,
0480:                                    "Sync service failed...", module);
0481:                        }
0482:                        String errMsg = "Service [" + modelService.name
0483:                                + "] threw an unexpected exception/error";
0484:                        Debug.logError(t, errMsg, module);
0485:                        engine.sendCallbacks(modelService, context, t,
0486:                                GenericEngine.SYNC_MODE);
0487:                        try {
0488:                            TransactionUtil.rollback(beganTrans, errMsg, t);
0489:                        } catch (GenericTransactionException te) {
0490:                            Debug.logError(te, "Cannot rollback transaction",
0491:                                    module);
0492:                        }
0493:                        checkDebug(modelService, 0, debugging);
0494:                        rs.setEndStamp();
0495:                        if (t instanceof  ServiceAuthException) {
0496:                            throw (ServiceAuthException) t;
0497:                        } else if (t instanceof  ServiceValidationException) {
0498:                            throw (ServiceValidationException) t;
0499:                        } else if (t instanceof  GenericServiceException) {
0500:                            throw (GenericServiceException) t;
0501:                        } else {
0502:                            throw new GenericServiceException("Service ["
0503:                                    + modelService.name + "] Failed"
0504:                                    + modelService.debugInfo(), t);
0505:                        }
0506:                    } finally {
0507:                        // if there was an error, rollback transaction, otherwise commit
0508:                        if (isError) {
0509:                            String errMsg = "Service Error ["
0510:                                    + modelService.name + "]: "
0511:                                    + ServiceUtil.getErrorMessage(result);
0512:                            // try to log the error
0513:                            Debug.logError(errMsg, module);
0514:
0515:                            // rollback the transaction
0516:                            try {
0517:                                TransactionUtil.rollback(beganTrans, errMsg,
0518:                                        null);
0519:                            } catch (GenericTransactionException e) {
0520:                                Debug.logError(e,
0521:                                        "Could not rollback transaction: "
0522:                                                + e.toString(), module);
0523:                            }
0524:                        } else {
0525:                            // commit the transaction
0526:                            try {
0527:                                TransactionUtil.commit(beganTrans);
0528:                            } catch (GenericTransactionException e) {
0529:                                String errMsg = "Could not commit transaction for service ["
0530:                                        + modelService.name + "] call";
0531:                                Debug.logError(e, errMsg, module);
0532:                                if (e.getMessage() != null) {
0533:                                    errMsg = errMsg + ": " + e.getMessage();
0534:                                }
0535:                                throw new GenericServiceException(errMsg);
0536:                            }
0537:                        }
0538:
0539:                        // call notifications -- event is determined from the result (success, error, fail)
0540:                        modelService.evalNotifications(this 
0541:                                .getLocalContext(localName), context, result);
0542:                    }
0543:                } catch (GenericTransactionException te) {
0544:                    Debug.logError(te, "Problems with the transaction", module);
0545:                    throw new GenericServiceException(
0546:                            "Problems with the transaction.", te.getNested());
0547:                } finally {
0548:                    // resume the parent transaction
0549:                    if (parentTransaction != null) {
0550:                        try {
0551:                            TransactionUtil.resume(parentTransaction);
0552:                        } catch (GenericTransactionException ite) {
0553:                            Debug.logWarning(ite,
0554:                                    "Transaction error, not resumed", module);
0555:                            throw new GenericServiceException(
0556:                                    "Resume transaction exception, see logs");
0557:                        }
0558:                    }
0559:                }
0560:
0561:                // pre-return ECA
0562:                if (eventMap != null)
0563:                    ServiceEcaUtil.evalRules(modelService.name, eventMap,
0564:                            "return", ctx, ecaContext, result, isError,
0565:                            isFailure);
0566:
0567:                checkDebug(modelService, 0, debugging);
0568:                rs.setEndStamp();
0569:
0570:                long timeToRun = System.currentTimeMillis() - serviceStartTime;
0571:                if (Debug.timingOn() && timeToRun > 50) {
0572:                    Debug.logTiming("Sync service [" + localName + "/"
0573:                            + modelService.name + "] finished in [" + timeToRun
0574:                            + "] milliseconds", module);
0575:                } else if (timeToRun > 200) {
0576:                    Debug.logInfo("Sync service [" + localName + "/"
0577:                            + modelService.name + "] finished in [" + timeToRun
0578:                            + "] milliseconds", module);
0579:                }
0580:
0581:                return result;
0582:            }
0583:
0584:            /**
0585:             * Run the service asynchronously, passing an instance of GenericRequester that will receive the result.
0586:             * @param localName Name of the context to use.
0587:             * @param service Service model object.
0588:             * @param context Map of name, value pairs composing the context.
0589:             * @param requester Object implementing GenericRequester interface which will receive the result.
0590:             * @param persist True for store/run; False for run.
0591:             * @throws ServiceAuthException
0592:             * @throws ServiceValidationException
0593:             * @throws GenericServiceException
0594:             */
0595:            public void runAsync(String localName, ModelService service,
0596:                    Map context, GenericRequester requester, boolean persist)
0597:                    throws ServiceAuthException, ServiceValidationException,
0598:                    GenericServiceException {
0599:                if (Debug.timingOn()) {
0600:                    UtilTimer.timerLog(localName + " / " + service.name,
0601:                            "ASync service started...", module);
0602:                }
0603:                boolean debugging = checkDebug(service, 1, true);
0604:                if (Debug.verboseOn()) {
0605:                    Debug.logVerbose(
0606:                            "[ServiceDispatcher.runAsync] : prepareing service "
0607:                                    + service.name + " [" + service.location
0608:                                    + "/" + service.invoke + "] ("
0609:                                    + service.engineName + ")", module);
0610:                }
0611:
0612:                if (context == null) {
0613:                    context = FastMap.newInstance();
0614:                }
0615:
0616:                // setup the result map
0617:                Map result = FastMap.newInstance();
0618:                boolean isFailure = false;
0619:                boolean isError = false;
0620:
0621:                // set up the running service log
0622:                this .logService(localName, service, GenericEngine.ASYNC_MODE);
0623:
0624:                // check the locale
0625:                Locale locale = this .checkLocale(context);
0626:
0627:                // setup the engine and context
0628:                DispatchContext ctx = (DispatchContext) localContext
0629:                        .get(localName);
0630:                GenericEngine engine = this 
0631:                        .getGenericEngine(service.engineName);
0632:
0633:                // for isolated transactions
0634:                Transaction parentTransaction = null;
0635:                // start the transaction
0636:                boolean beganTrans = false;
0637:
0638:                try {
0639:                    if (service.useTransaction) {
0640:                        beganTrans = TransactionUtil
0641:                                .begin(service.transactionTimeout);
0642:
0643:                        // isolate the transaction if defined
0644:                        if (service.requireNewTransaction && !beganTrans) {
0645:                            parentTransaction = TransactionUtil.suspend();
0646:                            // now start a new transaction
0647:                            beganTrans = TransactionUtil
0648:                                    .begin(service.transactionTimeout);
0649:                        }
0650:                    }
0651:
0652:                    // XAResource debugging
0653:                    if (beganTrans && TransactionUtil.debugResources) {
0654:                        DebugXaResource dxa = new DebugXaResource(service.name);
0655:                        try {
0656:                            dxa.enlist();
0657:                        } catch (Exception e) {
0658:                            Debug.logError(e, module);
0659:                        }
0660:                    }
0661:
0662:                    try {
0663:                        // get eventMap once for all calls for speed, don't do event calls if it is null
0664:                        Map eventMap = ServiceEcaUtil
0665:                                .getServiceEventMap(service.name);
0666:
0667:                        // pre-auth ECA
0668:                        if (eventMap != null)
0669:                            ServiceEcaUtil.evalRules(service.name, eventMap,
0670:                                    "auth", ctx, context, result, isError,
0671:                                    isFailure);
0672:
0673:                        context = checkAuth(localName, context, service);
0674:                        Object userLogin = context.get("userLogin");
0675:
0676:                        if (service.auth && userLogin == null)
0677:                            throw new ServiceAuthException(
0678:                                    "User authorization is required for this service: "
0679:                                            + service.name
0680:                                            + service.debugInfo());
0681:
0682:                        // pre-validate ECA
0683:                        if (eventMap != null)
0684:                            ServiceEcaUtil.evalRules(service.name, eventMap,
0685:                                    "in-validate", ctx, context, result,
0686:                                    isError, isFailure);
0687:
0688:                        // check for pre-validate failure/errors
0689:                        isFailure = ModelService.RESPOND_FAIL.equals(result
0690:                                .get(ModelService.RESPONSE_MESSAGE));
0691:                        isError = ModelService.RESPOND_ERROR.equals(result
0692:                                .get(ModelService.RESPONSE_MESSAGE));
0693:
0694:                        // validate the context
0695:                        if (service.validate && !isError && !isFailure) {
0696:                            try {
0697:                                service.validate(context,
0698:                                        ModelService.IN_PARAM, locale);
0699:                            } catch (ServiceValidationException e) {
0700:                                Debug
0701:                                        .logError(
0702:                                                e,
0703:                                                "Incoming service context (in runAsync: "
0704:                                                        + service.name
0705:                                                        + ") does not match expected requirements",
0706:                                                module);
0707:                                throw e;
0708:                            }
0709:                        }
0710:
0711:                        // run the service
0712:                        if (!isError && !isFailure) {
0713:                            if (requester != null) {
0714:                                engine.runAsync(localName, service, context,
0715:                                        requester, persist);
0716:                            } else {
0717:                                engine.runAsync(localName, service, context,
0718:                                        persist);
0719:                            }
0720:                            engine.sendCallbacks(service, context, null,
0721:                                    GenericEngine.ASYNC_MODE);
0722:                        }
0723:
0724:                        if (Debug.timingOn()) {
0725:                            UtilTimer.closeTimer(localName + " / "
0726:                                    + service.name,
0727:                                    "ASync service finished...", module);
0728:                        }
0729:                        checkDebug(service, 0, debugging);
0730:                    } catch (Throwable t) {
0731:                        if (Debug.timingOn()) {
0732:                            UtilTimer.closeTimer(localName + " / "
0733:                                    + service.name, "ASync service failed...",
0734:                                    module);
0735:                        }
0736:                        String errMsg = "Service [" + service.name
0737:                                + "] threw an unexpected exception/error";
0738:                        Debug.logError(t, errMsg, module);
0739:                        engine.sendCallbacks(service, context, t,
0740:                                GenericEngine.ASYNC_MODE);
0741:                        try {
0742:                            TransactionUtil.rollback(beganTrans, errMsg, t);
0743:                        } catch (GenericTransactionException te) {
0744:                            Debug.logError(te, "Cannot rollback transaction",
0745:                                    module);
0746:                        }
0747:                        checkDebug(service, 0, debugging);
0748:                        if (t instanceof  ServiceAuthException) {
0749:                            throw (ServiceAuthException) t;
0750:                        } else if (t instanceof  ServiceValidationException) {
0751:                            throw (ServiceValidationException) t;
0752:                        } else if (t instanceof  GenericServiceException) {
0753:                            throw (GenericServiceException) t;
0754:                        } else {
0755:                            throw new GenericServiceException("Service ["
0756:                                    + service.name + "] Failed"
0757:                                    + service.debugInfo(), t);
0758:                        }
0759:                    } finally {
0760:                        // always try to commit the transaction since we don't know in this case if its was an error or not
0761:                        try {
0762:                            TransactionUtil.commit(beganTrans);
0763:                        } catch (GenericTransactionException e) {
0764:                            Debug.logError(e, "Could not commit transaction",
0765:                                    module);
0766:                            throw new GenericServiceException(
0767:                                    "Commit transaction failed");
0768:                        }
0769:                    }
0770:                } catch (GenericTransactionException se) {
0771:                    Debug.logError(se, "Problems with the transaction", module);
0772:                    throw new GenericServiceException(
0773:                            "Problems with the transaction: " + se.getMessage()
0774:                                    + "; See logs for more detail");
0775:                } finally {
0776:                    // resume the parent transaction
0777:                    if (parentTransaction != null) {
0778:                        try {
0779:                            TransactionUtil.resume(parentTransaction);
0780:                        } catch (GenericTransactionException ise) {
0781:                            Debug.logError(ise,
0782:                                    "Trouble resuming parent transaction",
0783:                                    module);
0784:                            throw new GenericServiceException(
0785:                                    "Resume transaction exception: "
0786:                                            + ise.getMessage()
0787:                                            + "; See logs for more detail");
0788:                        }
0789:                    }
0790:                }
0791:            }
0792:
0793:            /**
0794:             * Run the service asynchronously and IGNORE the result.
0795:             * @param localName Name of the context to use.
0796:             * @param service Service model object.
0797:             * @param context Map of name, value pairs composing the context.
0798:             * @param persist True for store/run; False for run.
0799:             * @throws ServiceAuthException
0800:             * @throws ServiceValidationException
0801:             * @throws GenericServiceException
0802:             */
0803:            public void runAsync(String localName, ModelService service,
0804:                    Map context, boolean persist) throws ServiceAuthException,
0805:                    ServiceValidationException, GenericServiceException {
0806:                this .runAsync(localName, service, context, null, persist);
0807:            }
0808:
0809:            /**
0810:             * Gets the GenericEngine instance that corresponds to the given name
0811:             * @param engineName Name of the engine
0812:             * @return GenericEngine instance that corresponds to the engineName
0813:             */
0814:            public GenericEngine getGenericEngine(String engineName)
0815:                    throws GenericServiceException {
0816:                return factory.getGenericEngine(engineName);
0817:            }
0818:
0819:            /**
0820:             * Gets the JobManager associated with this dispatcher
0821:             * @return JobManager that is associated with this dispatcher
0822:             */
0823:            public JobManager getJobManager() {
0824:                return this .jm;
0825:            }
0826:
0827:            /**
0828:             * Gets the JmsListenerFactory which holds the message listeners.
0829:             * @return JmsListenerFactory
0830:             */
0831:            public JmsListenerFactory getJMSListenerFactory() {
0832:                return this .jlf;
0833:            }
0834:
0835:            /**
0836:             * Gets the GenericDelegator associated with this dispatcher
0837:             * @return GenericDelegator associated with this dispatcher
0838:             */
0839:            public GenericDelegator getDelegator() {
0840:                return this .delegator;
0841:            }
0842:
0843:            /**
0844:             * Gets the Security object associated with this dispatcher
0845:             * @return Security object associated with this dispatcher
0846:             */
0847:            public Security getSecurity() {
0848:                return this .security;
0849:            }
0850:
0851:            /**
0852:             * Gets the local context from a name
0853:             * @param name of the context to find.
0854:             */
0855:            public DispatchContext getLocalContext(String name) {
0856:                return (DispatchContext) localContext.get(name);
0857:            }
0858:
0859:            /**
0860:             * Gets the local dispatcher from a name
0861:             * @param name of the LocalDispatcher to find.
0862:             * @return LocalDispatcher matching the loader name
0863:             */
0864:            public LocalDispatcher getLocalDispatcher(String name) {
0865:                return ((DispatchContext) localContext.get(name))
0866:                        .getDispatcher();
0867:            }
0868:
0869:            /**
0870:             * Test if this dispatcher instance contains the local context.
0871:             * @param name of the local context
0872:             * @return true if the local context is found in this dispatcher.
0873:             */
0874:            public boolean containsContext(String name) {
0875:                return localContext.containsKey(name);
0876:            }
0877:
0878:            protected void shutdown() throws GenericServiceException {
0879:                Debug.logImportant("Shutting down the service engine...",
0880:                        module);
0881:                // shutdown JMS listeners
0882:                jlf.closeListeners();
0883:                // shutdown the job scheduler
0884:                jm.shutdown();
0885:            }
0886:
0887:            // checks if parameters were passed for authentication
0888:            private Map checkAuth(String localName, Map context,
0889:                    ModelService origService) throws ServiceAuthException,
0890:                    GenericServiceException {
0891:                String service = ServiceConfigUtil.getElementAttr(
0892:                        "authorization", "service-name");
0893:
0894:                if (service == null) {
0895:                    throw new GenericServiceException(
0896:                            "No Authentication Service Defined");
0897:                }
0898:                if (service.equals(origService.name)) {
0899:                    // manually calling the auth service, don't continue...
0900:                    return context;
0901:                }
0902:
0903:                if (context.containsKey("login.username")) {
0904:                    // check for a username/password, if there log the user in and make the userLogin object
0905:                    String username = (String) context.get("login.username");
0906:
0907:                    if (context.containsKey("login.password")) {
0908:                        String password = (String) context
0909:                                .get("login.password");
0910:
0911:                        context.put("userLogin", getLoginObject(service,
0912:                                localName, username, password, (Locale) context
0913:                                        .get("locale")));
0914:                        context.remove("login.password");
0915:                    } else {
0916:                        context.put("userLogin", getLoginObject(service,
0917:                                localName, username, null, (Locale) context
0918:                                        .get("locale")));
0919:                    }
0920:                    context.remove("login.username");
0921:                } else {
0922:                    // if a userLogin object is there, make sure the given username/password exists in our local database
0923:                    GenericValue userLogin = (GenericValue) context
0924:                            .get("userLogin");
0925:
0926:                    if (userLogin != null) {
0927:                        // 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...
0928:
0929:                        //The old way: GenericValue newUserLogin = getLoginObject(service, localName, userLogin.getString("userLoginId"), userLogin.getString("currentPassword"), (Locale) context.get("locale"));
0930:                        GenericValue newUserLogin = null;
0931:                        try {
0932:                            newUserLogin = this 
0933:                                    .getDelegator()
0934:                                    .findByPrimaryKeyCache(
0935:                                            "UserLogin",
0936:                                            UtilMisc
0937:                                                    .toMap(
0938:                                                            "userLoginId",
0939:                                                            userLogin
0940:                                                                    .get("userLoginId")));
0941:                        } catch (GenericEntityException e) {
0942:                            Debug.logError(e,
0943:                                    "Error looking up service authentication UserLogin: "
0944:                                            + e.toString(), module);
0945:                            // leave newUserLogin null, will be handled below
0946:                        }
0947:
0948:                        if (newUserLogin == null) {
0949:                            // uh oh, couldn't validate that one...
0950:                            // we'll have to remove it from the incoming context which will cause an auth error later if auth is required
0951:                            Debug
0952:                                    .logInfo(
0953:                                            "Service auth failed for userLoginId ["
0954:                                                    + userLogin
0955:                                                            .get("userLoginId")
0956:                                                    + "] because UserLogin record not found.",
0957:                                            module);
0958:                            context.remove("userLogin");
0959:                        } else if (newUserLogin.getString("currentPassword") != null
0960:                                && !newUserLogin
0961:                                        .getString("currentPassword")
0962:                                        .equals(
0963:                                                userLogin
0964:                                                        .getString("currentPassword"))) {
0965:                            // passwords didn't match, remove the userLogin for failed auth
0966:                            Debug
0967:                                    .logInfo(
0968:                                            "Service auth failed for userLoginId ["
0969:                                                    + userLogin
0970:                                                            .get("userLoginId")
0971:                                                    + "] because UserLogin record currentPassword fields did not match; note that the UserLogin object passed into a service may need to have the currentPassword encrypted.",
0972:                                            module);
0973:                            context.remove("userLogin");
0974:                        }
0975:                    }
0976:                }
0977:
0978:                // evaluate permissions for the service or throw exception if fail.
0979:                DispatchContext dctx = this .getLocalContext(localName);
0980:                if (UtilValidate.isNotEmpty(origService.permissionServiceName)) {
0981:                    Map permResp = origService.evalPermission(dctx, context);
0982:                    Boolean hasPermission = (Boolean) permResp
0983:                            .get("hasPermission");
0984:                    if (hasPermission == null) {
0985:                        throw new ServiceAuthException(
0986:                                "ERROR: the permission-service ["
0987:                                        + origService.permissionServiceName
0988:                                        + "] did not return a result. Not running the service ["
0989:                                        + origService.name + "]");
0990:                    }
0991:                    if (hasPermission.booleanValue()) {
0992:                        context.putAll(permResp);
0993:                        context = origService.makeValid(context,
0994:                                ModelService.IN_PARAM);
0995:                    } else {
0996:                        String message = (String) permResp.get("failMessage");
0997:                        if (UtilValidate.isEmpty(message)) {
0998:                            message = "You do not have permission to invoke the service ["
0999:                                    + origService.name + "]";
1000:                        }
1001:                        throw new ServiceAuthException(message);
1002:                    }
1003:                } else {
1004:                    if (!origService.evalPermissions(dctx, context)) {
1005:                        throw new ServiceAuthException(
1006:                                "You do not have permission to invoke the service ["
1007:                                        + origService.name + "]");
1008:                    }
1009:                }
1010:
1011:                return context;
1012:            }
1013:
1014:            // gets a value object from name/password pair
1015:            private GenericValue getLoginObject(String service,
1016:                    String localName, String username, String password,
1017:                    Locale locale) throws GenericServiceException {
1018:                Map context = UtilMisc.toMap("login.username", username,
1019:                        "login.password", password, "isServiceAuth",
1020:                        Boolean.TRUE, "locale", locale);
1021:
1022:                if (Debug.verboseOn())
1023:                    Debug
1024:                            .logVerbose(
1025:                                    "[ServiceDispathcer.authenticate] : Invoking UserLogin Service",
1026:                                    module);
1027:
1028:                // get the dispatch context and service model
1029:                DispatchContext dctx = getLocalContext(localName);
1030:                ModelService model = dctx.getModelService(service);
1031:
1032:                // get the service engine
1033:                GenericEngine engine = getGenericEngine(model.engineName);
1034:
1035:                // invoke the service and get the UserLogin value object
1036:                Map result = engine.runSync(localName, model, context);
1037:                return (GenericValue) result.get("userLogin");
1038:            }
1039:
1040:            // checks the locale object in the context
1041:            private Locale checkLocale(Map context) {
1042:                Object locale = context.get("locale");
1043:                Locale newLocale = null;
1044:
1045:                if (locale != null) {
1046:                    if (locale instanceof  Locale) {
1047:                        return (Locale) locale;
1048:                    } else if (locale instanceof  String) {
1049:                        // en_US = lang_COUNTRY
1050:                        newLocale = UtilMisc.parseLocale((String) locale);
1051:                    }
1052:                }
1053:
1054:                if (newLocale == null) {
1055:                    newLocale = Locale.getDefault();
1056:                }
1057:                context.put("locale", newLocale);
1058:                return newLocale;
1059:            }
1060:
1061:            // mode 1 = beginning (turn on) mode 0 = end (turn off)
1062:            private boolean checkDebug(ModelService model, int mode,
1063:                    boolean enable) {
1064:                boolean debugOn = Debug.verboseOn();
1065:                switch (mode) {
1066:                case 0:
1067:                    if (model.debug && enable && debugOn) {
1068:                        // turn it off
1069:                        Debug.set(Debug.VERBOSE, false);
1070:                        Debug.logInfo("Verbose logging turned OFF", module);
1071:                        return true;
1072:                    }
1073:                    break;
1074:                case 1:
1075:                    if (model.debug && enable && !debugOn) {
1076:                        // turn it on
1077:                        Debug.set(Debug.VERBOSE, true);
1078:                        Debug.logInfo("Verbose logging turned ON", module);
1079:                        return true;
1080:                    }
1081:                    break;
1082:                default:
1083:                    Debug.logError(
1084:                            "Invalid mode for checkDebug should be (0 or 1)",
1085:                            module);
1086:                }
1087:                return false;
1088:            }
1089:
1090:            // run startup services
1091:            private synchronized int runStartupServices() {
1092:                if (jm == null)
1093:                    return 0;
1094:
1095:                Element root;
1096:                try {
1097:                    root = ServiceConfigUtil.getXmlRootElement();
1098:                } catch (GenericConfigException e) {
1099:                    Debug.logError(e, module);
1100:                    return 0;
1101:                }
1102:
1103:                int servicesScheduled = 0;
1104:                List startupServices = UtilXml.childElementList(root,
1105:                        "startup-service");
1106:                if (startupServices != null && startupServices.size() > 0) {
1107:                    Iterator i = startupServices.iterator();
1108:                    while (i.hasNext()) {
1109:                        Element ss = (Element) i.next();
1110:                        String serviceName = ss.getAttribute("name");
1111:                        String runtimeDataId = ss
1112:                                .getAttribute("runtime-data-id");
1113:                        String delayStr = ss.getAttribute("runtime-delay");
1114:                        String sendToPool = ss.getAttribute("run-in-pool");
1115:                        if (UtilValidate.isEmpty(sendToPool)) {
1116:                            sendToPool = ServiceConfigUtil.getSendPool();
1117:                        }
1118:
1119:                        long runtimeDelay;
1120:                        try {
1121:                            runtimeDelay = Long.parseLong(delayStr);
1122:                        } catch (Exception e) {
1123:                            Debug
1124:                                    .logError(
1125:                                            e,
1126:                                            "Unable to parse runtime-delay value; using 0",
1127:                                            module);
1128:                            runtimeDelay = 0;
1129:                        }
1130:
1131:                        // current time + 1 sec delay + extended delay
1132:                        long runtime = System.currentTimeMillis() + 1000
1133:                                + runtimeDelay;
1134:                        try {
1135:                            jm.schedule(sendToPool, serviceName, runtimeDataId,
1136:                                    runtime);
1137:                        } catch (JobManagerException e) {
1138:                            Debug.logError(e, "Unable to schedule service ["
1139:                                    + serviceName + "]", module);
1140:                        }
1141:                    }
1142:                }
1143:
1144:                return servicesScheduled;
1145:            }
1146:
1147:            private RunningService logService(String localName,
1148:                    ModelService modelService, int mode) {
1149:                // set up the running service log
1150:                RunningService rs = new RunningService(localName, modelService,
1151:                        mode);
1152:                if (runLog == null) {
1153:                    runLog = new LRUMap(lruLogSize);
1154:                }
1155:                try {
1156:                    runLog.put(rs, this );
1157:                } catch (Throwable t) {
1158:                    Debug.logWarning("LRUMap problem; resetting LRU ["
1159:                            + runLog.size() + "]", module);
1160:                    runLog = new LRUMap(lruLogSize);
1161:                    try {
1162:                        runLog.put(rs, this );
1163:                    } catch (Throwable t2) {
1164:                        Debug.logError(t2, "Unable to put() in reset LRU map!",
1165:                                module);
1166:                    }
1167:                }
1168:                return rs;
1169:            }
1170:
1171:            /**
1172:             * Enabled/Disables the Job Manager/Scheduler globally
1173:             * (this will not effect any dispatchers already running)
1174:             * @param enable
1175:             */
1176:            public static void enableJM(boolean enable) {
1177:                ServiceDispatcher.enableJM = enable;
1178:            }
1179:
1180:            /**
1181:             * Enabled/Disables the JMS listeners globally
1182:             * (this will not effect any dispatchers already running)
1183:             * @param enable
1184:             */
1185:            public static void enableJMS(boolean enable) {
1186:                ServiceDispatcher.enableJMS = enable;
1187:            }
1188:
1189:            /**
1190:             * Enabled/Disables the startup services globally
1191:             * (this will not effect any dispatchers already running)
1192:             * @param enable
1193:             */
1194:            public static void enableSvcs(boolean enable) {
1195:                ServiceDispatcher.enableSvcs = enable;
1196:            }
1197:
1198:            public static Map getServiceLogMap() {
1199:                return runLog;
1200:            }
1201:
1202:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.