You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jl...@apache.org on 2014/09/08 08:04:42 UTC

svn commit: r1623295 [3/5] - in /ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23: ./ applications/accounting/config/ applications/content/config/ applications/content/data/ applications/content/src/org/ofbiz/content/ applications/content/src/o...

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/workeffort/webapp/workeffort/WEB-INF/actions/calendar/Upcoming.groovy
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/workeffort/webapp/workeffort/WEB-INF/actions/calendar/Upcoming.groovy?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/workeffort/webapp/workeffort/WEB-INF/actions/calendar/Upcoming.groovy (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/workeffort/webapp/workeffort/WEB-INF/actions/calendar/Upcoming.groovy Mon Sep  8 06:04:39 2014
@@ -18,11 +18,7 @@
  */
 
 import java.util.*;
-import org.ofbiz.security.*;
-import org.ofbiz.entity.*;
 import org.ofbiz.base.util.*;
-import org.ofbiz.webapp.pseudotag.*;
-import org.ofbiz.workeffort.workeffort.*;
 
 facilityId = parameters.get("facilityId");
 fixedAssetId = parameters.get("fixedAssetId");

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/config/log4j2.xml
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/config/log4j2.xml?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/config/log4j2.xml (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/config/log4j2.xml Mon Sep  8 06:04:39 2014
@@ -2,11 +2,11 @@
 <Configuration monitorInterval="60">
     <Appenders>
         <Console name="stdout" target="SYSTEM_OUT">
-            <PatternLayout pattern="%date{COMPACT} |%-20.20thread |%-20.20logger{1}|%level{length=1}| %message%n"/>
+            <PatternLayout pattern="%date{COMPACT} |%-20.20thread |%-30.30logger{1}|%level{length=1}| %message%n"/>
         </Console>
         <RollingFile name="ofbiz" fileName="runtime/logs/ofbiz.log"
                      filePattern="runtime/logs/ofbiz-%d{yyyy-MM-dd}-%i.log.zip">
-            <PatternLayout pattern="%date{COMPACT} |%-20.20thread |%-20.20logger{1}|%level{length=1}| %message%n"/>
+            <PatternLayout pattern="%date{COMPACT} |%-20.20thread |%-30.30logger{1}|%level{length=1}| %message%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="1 MB"/>
@@ -15,7 +15,7 @@
         </RollingFile>
         <RollingFile name="external" fileName="runtime/logs/external.log"
                      filePattern="runtime/logs/external-%d{yyyy-MM-dd}-%i.log.zip">
-            <PatternLayout pattern="%date{COMPACT} |%-20.20thread |%-20.20logger{1}|%level{length=1}| %message%n"/>
+            <PatternLayout pattern="%date{COMPACT} |%-20.20thread |%-30.30logger{1}|%level{length=1}| %message%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="1 MB"/>

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/src/org/ofbiz/base/util/Debug.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/src/org/ofbiz/base/util/Debug.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/src/org/ofbiz/base/util/Debug.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/base/src/org/ofbiz/base/util/Debug.java Mon Sep  8 06:04:39 2014
@@ -18,17 +18,11 @@
  *******************************************************************************/
 package org.ofbiz.base.util;
 
-import java.io.PrintStream;
-import java.io.PrintWriter;
 import java.util.Formatter;
 import java.util.HashMap;
-import java.util.Locale;
 import java.util.Map;
-import java.util.TimeZone;
 
 import org.apache.logging.log4j.*;
-import org.ofbiz.base.conversion.ConversionException;
-import org.ofbiz.base.conversion.DateTimeConverters.DateToString;
 
 /**
  * Configurable Debug logging wrapper class
@@ -36,11 +30,9 @@ import org.ofbiz.base.conversion.DateTim
  */
 public final class Debug {
 
-    public static final boolean useLog4J = true;
-    public static final String noModuleModule = "NoModule";  // set to null for previous behavior
-    public static final Object[] emptyParams = new Object[0];
+    private static final String noModuleModule = "NoModule";  // set to null for previous behavior
+    private static final Object[] emptyParams = new Object[0];
 
-    public static final String SYS_DEBUG = System.getProperty("DEBUG");
     public static final int ALWAYS = 0;
     public static final int VERBOSE = 1;
     public static final int TIMING = 2;
@@ -50,19 +42,14 @@ public final class Debug {
     public static final int ERROR = 6;
     public static final int FATAL = 7;
 
-    public static final String[] levels = {"Always", "Verbose", "Timing", "Info", "Important", "Warning", "Error", "Fatal"};
-    public static final String[] levelProps = {"", "print.verbose", "print.timing", "print.info", "print.important", "print.warning", "print.error", "print.fatal"};
-    public static final Level[] levelObjs = {Level.FATAL, Level.DEBUG, Level.TRACE, Level.INFO, Level.INFO, Level.WARN, Level.ERROR, Level.FATAL};
+    private static final String[] levelProps = {"", "print.verbose", "print.timing", "print.info", "print.important", "print.warning", "print.error", "print.fatal"};
+    private static final Level[] levelObjs = {Level.FATAL, Level.DEBUG, Level.TRACE, Level.INFO, Level.INFO, Level.WARN, Level.ERROR, Level.FATAL};
 
-    protected static Map<String, Integer> levelStringMap = new HashMap<String, Integer>();
+    private static final Map<String, Integer> levelStringMap = new HashMap<String, Integer>();
 
-    protected static PrintStream printStream = System.out;
-    protected static PrintWriter printWriter = new PrintWriter(printStream);
+    private static final boolean levelOnCache[] = new boolean[8]; // this field is not thread safe
 
-    protected static boolean levelOnCache[] = new boolean[8];
-    protected static final boolean useLevelOnCache = true;
-
-    protected static Logger root = LogManager.getRootLogger();
+    private static final Logger root = LogManager.getRootLogger();
 
     static {
         levelStringMap.put("verbose", Debug.VERBOSE);
@@ -80,19 +67,6 @@ public final class Debug {
         }
     }
 
-    public static PrintStream getPrintStream() {
-        return printStream;
-    }
-
-    public static void setPrintStream(PrintStream printStream) {
-        Debug.printStream = printStream;
-        Debug.printWriter = new PrintWriter(printStream);
-    }
-
-    public static PrintWriter getPrintWriter() {
-        return printWriter;
-    }
-
     public static Logger getLogger(String module) {
         if (UtilValidate.isNotEmpty(module)) {
             return LogManager.getLogger(module);
@@ -129,47 +103,13 @@ public final class Debug {
             }
 
             // log
-            if (useLog4J) {
-                Logger logger = getLogger(module);
-                //callingClass
-                logger.log(levelObjs[level], msg, t);
-            } else {
-                StringBuilder prefixBuf = new StringBuilder();
-
-                DateToString dateToString = new DateToString(); 
-                try {
-                    prefixBuf.append(dateToString.convert(new java.util.Date(), Locale.getDefault(), 
-                            TimeZone.getDefault(), UtilDateTime.DATE_TIME_FORMAT));
-                } catch (ConversionException e) {
-                    logFatal(e, Debug.class.getName());
-                }
-                prefixBuf.append(" [OFBiz");
-                if (module != null) {
-                    prefixBuf.append(":");
-                    prefixBuf.append(module);
-                }
-                prefixBuf.append(":");
-                prefixBuf.append(levels[level]);
-                prefixBuf.append("] ");
-                if (msg != null) {
-                    getPrintWriter().print(prefixBuf.toString());
-                    getPrintWriter().println(msg);
-                }
-                if (t != null) {
-                    getPrintWriter().print(prefixBuf.toString());
-                    getPrintWriter().println("Received throwable:");
-                    t.printStackTrace(getPrintWriter());
-                }
-            }
+            Logger logger = getLogger(module);
+            logger.log(levelObjs[level], msg, t);
         }
     }
 
     public static boolean isOn(int level) {
-        if (useLevelOnCache) {
-            return levelOnCache[level];
-        } else {
-            return (level == Debug.ALWAYS || UtilProperties.propertyValueEqualsIgnoreCase("debug.properties", levelProps[level], "true"));
-        }
+        return levelOnCache[level];
     }
 
     // leaving these here
@@ -374,14 +314,10 @@ public final class Debug {
     }
 
     public static void set(int level, boolean on) {
-        if (!useLevelOnCache)
-            return;
         levelOnCache[level] = on;
     }
 
     public static boolean get(int level) {
-        if (!useLevelOnCache)
-            return true;
         return levelOnCache[level];
     }
 }

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonEntityLabels.xml
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonEntityLabels.xml?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonEntityLabels.xml (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonEntityLabels.xml Mon Sep  8 06:04:39 2014
@@ -16266,7 +16266,7 @@
         <value xml:lang="ru">Афгани</value>
         <value xml:lang="th">อัฟกานิ </value>
         <value xml:lang="zh">阿富汗尼</value>
-        <value xml:lang="zh_TW">阿富汗</value>
+        <value xml:lang="zh_TW">阿富汗尼</value>
     </property>
     <property key="Uom.description.ALL">
         <value xml:lang="de">Lek Albanien</value>
@@ -20653,7 +20653,7 @@
         <value xml:lang="th">สกุลเงิน</value>
         <value xml:lang="vi">Tiền tệ</value>
         <value xml:lang="zh">币种</value>
-        <value xml:lang="zh_TW">幣別</value>
+        <value xml:lang="zh_TW">度量單位</value>
     </property>
     <property key="UomType.description.DATASPD_MEASURE">
         <value xml:lang="de">Daten Geschwindigkeit</value>

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonUiLabels.xml
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonUiLabels.xml?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonUiLabels.xml (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/common/config/CommonUiLabels.xml Mon Sep  8 06:04:39 2014
@@ -118,7 +118,7 @@
         <value xml:lang="th">CMS Site</value>
         <value xml:lang="vi">Trang thông tin CMS</value>
         <value xml:lang="zh">内容管理系统站点</value>
-        <value xml:lang="zh_TW">內容管理系統</value>
+        <value xml:lang="zh_TW">內容管理系統站台</value>
     </property>
     <property key="Catalog">
         <value xml:lang="ar">كاتالوج</value>
@@ -2421,7 +2421,7 @@
         <value xml:lang="vi">Tiền tệ</value>
         <value xml:lang="zh">币种</value>
         <value xml:lang="zh-CN">货币</value>
-        <value xml:lang="zh_TW">幣別</value>
+        <value xml:lang="zh_TW">度量單位</value>
     </property>
     <property key="CommonCurrent">
         <value xml:lang="ar">جاري</value>
@@ -8118,7 +8118,6 @@
         <value xml:lang="es">Ejecutar</value>
         <value xml:lang="fr">Exécuter</value>
         <value xml:lang="hi-IN">प्रर्दशित करे</value>
-        <value xml:lang="zh_TW">PDF</value>
         <value xml:lang="it">Esegui</value>
         <value xml:lang="ja">実行</value>
         <value xml:lang="nl">Uitvoeren</value>
@@ -10962,7 +10961,7 @@
         <value xml:lang="th">ที่</value>
         <value xml:lang="vi">Cái</value>
         <value xml:lang="zh"> </value>
-        <value xml:lang="zh">æ­¤</value>
+        <value xml:lang="zh_TW">æ­¤</value>
     </property>
     <property key="CommonTheFollowingRequiredFieldsWhereFoundEmpty">
         <value xml:lang="cs">Následující povinná pole byla prázdná</value>
@@ -13143,7 +13142,7 @@
         <value xml:lang="th">สกุลเงิน</value>
         <value xml:lang="vi">Tiền tệ</value>
         <value xml:lang="zh">币种</value>
-        <value xml:lang="zh_TW">幣別</value>
+        <value xml:lang="zh_TW">度量單位</value>
     </property>
     <property key="FormFieldTitle_currentRecurrenceCount">
         <value xml:lang="cs">Současná hloubka zanoření</value>
@@ -13834,7 +13833,7 @@
         <value xml:lang="th">หน่วยวัด</value>
         <value xml:lang="vi">Đơn vị tính</value>
         <value xml:lang="zh">币值</value>
-        <value xml:lang="zh_TW">幣別</value>
+        <value xml:lang="zh_TW">度量單位</value>
     </property>
     <property key="FormFieldTitle_updateButton">
         <value xml:lang="ar">تحديث</value>
@@ -13870,7 +13869,6 @@
         <value xml:lang="en">HR</value>
         <value xml:lang="es">RR.HH.</value>
         <value xml:lang="fr">Ress. hum.</value>
-        <value xml:lang="zh_TW">Google Base</value>
         <value xml:lang="hi-IN">मानव संसाधन(HR)</value>
         <value xml:lang="it">Risorse umane</value>
         <value xml:lang="ja">人事(HR)</value>
@@ -14011,7 +14009,6 @@
         <value xml:lang="fr">Commandes</value>
         <value xml:lang="hi-IN">आदेश</value>
         <value xml:lang="it">Ordini</value>
-        <value xml:lang="zh_TW">Oagis</value>
         <value xml:lang="ja">注文</value>
         <value xml:lang="nl">Bestelling</value>
         <value xml:lang="pt">Encomenda</value>

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java Mon Sep  8 06:04:39 2014
@@ -45,7 +45,6 @@ import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilXml;
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.DelegatorFactory;
-import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntity;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericPK;
@@ -1152,6 +1151,64 @@ public class EntityTestSuite extends Ent
         assertFalse("Duplicate sequence id returned", duplicateFound.get());
     }
 
+    /*
+        This test is useful to confirm that the default setting of use-transaction="true" for screen definitions is
+        the best one for performance.
+        With this setting one database transaction is started by the framework before rendering the screen.
+        Most screens usually have multiple Delegator calls to find records.
+        In most of the GenericDelegator's find methods, a transaction is created if one does not already exist,
+        the statement is performed, and the transaction is committed.
+        So, by making that attribute "false" - a screen will have many individual transactions instead of just one.
+
+        This test assess that running the same number of sql statements withing one transaction is faster than running
+        them with individual transactions.
+     */
+    public void testOneBigTransactionIsFasterThanSeveralSmallOnes() {
+        boolean transactionStarted = false;
+        long startTime = System.currentTimeMillis();
+        int totalNumberOfRows = 0;
+        int numberOfQueries = 500;
+        boolean noErrors = true;
+        try {
+            transactionStarted = TransactionUtil.begin();
+            for (int i = 1; i <= numberOfQueries; i++) {
+                List rows = delegator.findAll("SequenceValueItem", false);
+                totalNumberOfRows = totalNumberOfRows + rows.size();
+            }
+            TransactionUtil.commit(transactionStarted);
+        } catch (Exception e) {
+            try {
+                TransactionUtil.rollback(transactionStarted, "", e);
+            } catch (Exception e2) {}
+            noErrors = false;
+        }
+        long endTime = System.currentTimeMillis();
+        long totalTimeOneTransaction = endTime - startTime;
+        Debug.logInfo("Selected " + totalNumberOfRows + " rows with " + numberOfQueries + " queries (all contained in one big transaction) in " + totalTimeOneTransaction + " ms", module);
+        assertTrue("Errors detected executing the big transaction", noErrors);
+
+        totalNumberOfRows = 0;
+        noErrors = true;
+        try {
+            for (int i = 1; i <= numberOfQueries; i++) {
+                transactionStarted = TransactionUtil.begin();
+                List rows = delegator.findAll("SequenceValueItem", false);
+                totalNumberOfRows = totalNumberOfRows + rows.size();
+                TransactionUtil.commit(transactionStarted);
+            }
+        } catch (Exception e) {
+            try {
+                TransactionUtil.rollback(transactionStarted, "", e);
+            } catch (Exception e2) {}
+            noErrors = false;
+        }
+        endTime = System.currentTimeMillis();
+        long totalTimeSeveralSmallTransactions = endTime - startTime;
+        Debug.logInfo("Selected " + totalNumberOfRows + " rows with " + numberOfQueries + " queries (each in its own transaction) in " + totalTimeSeveralSmallTransactions + " ms", module);
+        assertTrue("Errors detected executing the small transactions", noErrors);
+        assertTrue("One big transaction was not faster than several small ones", totalTimeOneTransaction < totalTimeSeveralSmallTransactions);
+    }
+
     private final class TestObserver implements Observer {
         private Observable observable;
         private Object arg;

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java Mon Sep  8 06:04:39 2014
@@ -155,9 +155,19 @@ public class SequenceUtil {
             this.fillBank(staggerMax);
         }
 
+        /*
+           The algorithm to get the new sequence id in a thread safe way is the following:
+           1 - run an update with no changes to get a lock on the record
+               1bis - if no record is found, try to create and update it to get the lock
+           2 - select the record (now locked) to get the curSeqId
+           3 - increment the sequence
+           The three steps are executed in one dedicated database transaction.
+         */
         private void fillBank(long stagger) {
             // no need to get a new bank, SeqIds available
-            if ((curSeqId + stagger) <= maxSeqId) return;
+            if ((curSeqId + stagger) <= maxSeqId) {
+                return;
+            }
 
             long bankSize = this.bankSize;
             if (stagger > 1) {
@@ -165,7 +175,9 @@ public class SequenceUtil {
                 bankSize = stagger * defaultBankSize;
             }
 
-            if (bankSize > maxBankSize) bankSize = maxBankSize;
+            if (bankSize > maxBankSize) {
+                bankSize = maxBankSize;
+            }
 
             Transaction suspendedTransaction = null;
             try {
@@ -192,34 +204,35 @@ public class SequenceUtil {
                         throw new GenericEntityException("Unable to esablish a connection with the database, connection was null...");
                     }
 
-                    String sql = null;
                     try {
                         stmt = connection.createStatement();
-
-                        // run an update with no changes to get a lock on the record
+                        String sql = null;
+                        // 1 - run an update with no changes to get a lock on the record
                         if (stmt.executeUpdate(updateForLockStatement) <= 0) {
-                            Debug.logWarning("First select failed: will try to add new row, result set was empty for sequence [" + seqName + "] \nUsed SQL: " + sql + " \n ", module);
+                            Debug.logWarning("Lock failed; no sequence row was found, will try to add a new one for sequence: " + seqName, module);
                             sql = "INSERT INTO " + SequenceUtil.this.tableName + " (" + SequenceUtil.this.nameColName + ", " + SequenceUtil.this.idColName + ") VALUES ('" + this.seqName + "', " + startSeqId + ")";
-                            if (stmt.executeUpdate(sql) <= 0) {
+                            try {
+                                stmt.executeUpdate(sql);
+                            } catch (SQLException sqle) {
                                 // insert failed: this means that another thread inserted the record; then retry to run an update with no changes to get a lock on the record
                                 if (stmt.executeUpdate(updateForLockStatement) <= 0) {
                                     // This should never happen
-                                    throw new GenericEntityException("No rows changed when trying insert new sequence row with this SQL: " + sql);
+                                    throw new GenericEntityException("No rows changed when trying insert new sequence: " + seqName);
                                 }
+
                             }
                         }
-                        // select the record (now locked) to get the curSeqId
+                        // 2 - select the record (now locked) to get the curSeqId
                         rs = stmt.executeQuery(selectSequenceStatement);
-                        boolean gotVal = false;
-                        if (rs.next()) {
+                        boolean sequenceFound = rs.next();
+                        if (sequenceFound) {
                             curSeqId = rs.getLong(SequenceUtil.this.idColName);
-                            gotVal = true;
                         }
                         rs.close();
-                        if (!gotVal) {
-                            throw new GenericEntityException("Failed to find the sequence record: " + sql);
+                        if (!sequenceFound) {
+                            throw new GenericEntityException("Failed to find the sequence record for sequence: " + seqName);
                         }
-                        // increment the sequence
+                        // 3 - increment the sequence
                         sql = "UPDATE " + SequenceUtil.this.tableName + " SET " + SequenceUtil.this.idColName + "=" + SequenceUtil.this.idColName + "+" + bankSize + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
                         if (stmt.executeUpdate(sql) <= 0) {
                             throw new GenericEntityException("Update failed, no rows changes for seqName: " + seqName);

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaUtil.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaUtil.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/src/org/ofbiz/entityext/eca/EntityEcaUtil.java Mon Sep  8 06:04:39 2014
@@ -24,7 +24,6 @@ import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Future;
 
-import freemarker.template.utility.StringUtil;
 import javolution.util.FastList;
 import javolution.util.FastMap;
 
@@ -135,7 +134,7 @@ public class EntityEcaUtil {
             rules.add(new EntityEcaRule(e));
         }
         try {
-            Debug.logInfo("Loaded [" + StringUtil.leftPad(Integer.toString(rules.size()), 3) + "] Entity ECA definitions from " + handler.getFullLocation() + " in loader " + handler.getLoaderName(), module);
+            Debug.logInfo("Loaded [" + rules.size() + "] Entity ECA definitions from " + handler.getFullLocation() + " in loader " + handler.getLoaderName(), module);
         } catch (GenericConfigException e) {
             Debug.logError(e, module);
         }

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/DispatchContext.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/DispatchContext.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/DispatchContext.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/DispatchContext.java Mon Sep  8 06:04:39 2014
@@ -19,86 +19,28 @@
 package org.ofbiz.service;
 
 import java.io.Serializable;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
 
 import javax.wsdl.WSDLException;
 
-import org.ofbiz.base.component.ComponentConfig;
-import org.ofbiz.base.concurrent.ExecutionPool;
-import org.ofbiz.base.config.GenericConfigException;
-import org.ofbiz.base.config.MainResourceHandler;
-import org.ofbiz.base.config.ResourceHandler;
-import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.cache.UtilCache;
 import org.ofbiz.entity.Delegator;
-import org.ofbiz.entity.GenericEntityConfException;
-import org.ofbiz.entity.config.model.DelegatorElement;
-import org.ofbiz.entity.config.model.EntityConfig;
 import org.ofbiz.security.Security;
-import org.ofbiz.service.config.ServiceConfigUtil;
-import org.ofbiz.service.config.model.GlobalServices;
-import org.ofbiz.service.eca.ServiceEcaUtil;
 import org.w3c.dom.Document;
 
 /**
- * Dispatcher Context
+ * Service dispatch context. A collection of objects and convenience methods
+ * to be used by service implementations.
  */
 @SuppressWarnings("serial")
-public class DispatchContext implements Serializable {
+public final class DispatchContext implements Serializable {
 
     public static final String module = DispatchContext.class.getName();
 
-    private static final UtilCache<String, Map<String, ModelService>> modelServiceMapByModel = UtilCache.createUtilCache("service.ModelServiceMapByModel", 0, 0, false);
+    private final LocalDispatcher dispatcher;
 
-    // these four fields represent the immutable state of a DispatchContext object
-    private final String name;
-    private final transient ClassLoader loader;
-    private final transient LocalDispatcher dispatcher;
-    private final String model;
-
-    /**
-     * Creates new DispatchContext as an immutable object.
-     * The "dispatcher" argument can be null if the "name" argument matches the name of a valid entity model reader.
-     * The thread safety of a DispatchContext object is a consequence of its immutability.
-     *
-     * @param name The immutable name of the DispatchContext
-     * @param loader The immutable class loader
-     * @param dispatcher The immutable dispatcher associated to the DispatchContext
-     *
-     */
-    public DispatchContext(String name, ClassLoader loader, LocalDispatcher dispatcher) {
-        this.name = name;
-        this.loader = loader;
+    DispatchContext(LocalDispatcher dispatcher) {
         this.dispatcher = dispatcher;
-        String modelName = null;
-        if (this.dispatcher != null) {
-            Delegator delegator = dispatcher.getDelegator();
-            if (delegator != null) {
-                DelegatorElement delegatorInfo = null;
-                try {
-                    delegatorInfo = EntityConfig.getInstance().getDelegator(delegator.getDelegatorBaseName());
-                } catch (GenericEntityConfException e) {
-                    Debug.logWarning(e, "Exception thrown while getting delegator config: ", module);
-                }
-                if (delegatorInfo != null) {
-                    modelName = delegatorInfo.getEntityModelReader();
-                }
-            }
-        }
-        if (modelName == null) {
-            // if a modelName is not associated to the dispatcher (e.g. dispatcher is null) then use the name
-            // of the DispatchContext as the model reader name
-            modelName = name;
-        }
-        this.model = modelName;
-        getGlobalServiceMap();
     }
 
     /**
@@ -106,7 +48,7 @@ public class DispatchContext implements 
      * @return ClassLoader of the context
      */
     public ClassLoader getClassLoader() {
-        return this.loader;
+        return dispatcher.getClassLoader();
     }
 
     /**
@@ -114,7 +56,7 @@ public class DispatchContext implements 
      * @return String name of the LocalDispatcher object
      */
     public String getName() {
-        return name;
+        return dispatcher.getName();
     }
 
     /**
@@ -122,7 +64,7 @@ public class DispatchContext implements 
      * @return LocalDispatcher that was used to create this context
      */
     public LocalDispatcher getDispatcher() {
-        return this.dispatcher;
+        return dispatcher;
     }
 
     /**
@@ -199,84 +141,20 @@ public class DispatchContext implements 
     }
 
     /**
-     * Gets the ModelService instance that corresponds to given the name
+     * Gets the ModelService instance that corresponds to the given name
      * @param serviceName Name of the service
      * @return GenericServiceModel that corresponds to the serviceName
      */
     public ModelService getModelService(String serviceName) throws GenericServiceException {
-        Map<String, ModelService> serviceMap = getGlobalServiceMap();
-        ModelService retVal = null;
-        if (serviceMap != null) {
-            retVal = serviceMap.get(serviceName);
-            if (retVal != null && !retVal.inheritedParameters()) {
-                retVal.interfaceUpdate(this);
-            }
-        }
-        if (retVal == null) {
-            throw new GenericServiceException("Cannot locate service by name (" + serviceName + ")");
-        }
-        return retVal;
+        return dispatcher.getModelService(serviceName);
     }
 
     public Set<String> getAllServiceNames() {
-        Set<String> serviceNames = new TreeSet<String>();
-
-        Map<String, ModelService> globalServices = modelServiceMapByModel.get(this.model);
-        if (globalServices != null) {
-            serviceNames.addAll(globalServices.keySet());
-        }
-        return serviceNames;
+        return dispatcher.getAllServiceNames();
     }
 
     public Document getWSDL(String serviceName, String locationURI) throws GenericServiceException, WSDLException {
         ModelService model = this.getModelService(serviceName);
         return model.toWSDL(locationURI);
     }
-
-    private Callable<Map<String, ModelService>> createServiceReaderCallable(final ResourceHandler handler) {
-        return new Callable<Map<String, ModelService>>() {
-            public Map<String, ModelService> call() throws Exception {
-                return ModelServiceReader.getModelServiceMap(handler, DispatchContext.this.getDelegator());
-            }
-        };
-    }
-
-    private Map<String, ModelService> getGlobalServiceMap() {
-        Map<String, ModelService> serviceMap = modelServiceMapByModel.get(this.model);
-        if (serviceMap == null) {
-            serviceMap = new HashMap<String, ModelService>();
-
-            List<Future<Map<String, ModelService>>> futures = new LinkedList<Future<Map<String, ModelService>>>();
-            List<GlobalServices> globalServicesList = null;
-            try {
-                globalServicesList = ServiceConfigUtil.getServiceEngine().getGlobalServices();
-            } catch (GenericConfigException e) {
-                // FIXME: Refactor API so exceptions can be thrown and caught.
-                Debug.logError(e, module);
-                throw new RuntimeException(e.getMessage());
-            }
-            for (GlobalServices globalServices : globalServicesList) {
-                ResourceHandler handler = new MainResourceHandler(ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME, globalServices.getLoader(), globalServices.getLocation());
-                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(handler)));
-            }
-
-            // get all of the component resource model stuff, ie specified in each ofbiz-component.xml file
-            for (ComponentConfig.ServiceResourceInfo componentResourceInfo: ComponentConfig.getAllServiceResourceInfos("model")) {
-                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(componentResourceInfo.createResourceHandler())));
-            }
-            for (Map<String, ModelService> servicesMap: ExecutionPool.getAllFutures(futures)) {
-                if (servicesMap != null) {
-                    serviceMap.putAll(servicesMap);
-                }
-            }
-
-            if (serviceMap != null) {
-                Map<String, ModelService> cachedServiceMap = modelServiceMapByModel.putIfAbsentAndGet(this.model, serviceMap);
-                if (cachedServiceMap == serviceMap) { // same object: this means that the object created by this thread was actually added to the cache
-                    ServiceEcaUtil.reloadConfig();
-                }
-            }
-        }
-        return serviceMap;
-    }
 }

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericAbstractDispatcher.java Mon Sep  8 06:04:39 2014
@@ -40,8 +40,7 @@ public abstract class GenericAbstractDis
 
     public static final String module = GenericAbstractDispatcher.class.getName();
 
-    protected DispatchContext ctx = null;
-    protected ServiceDispatcher dispatcher = null;
+    protected ServiceDispatcher globalDispatcher = null;
     protected String name = null;
 
     public GenericAbstractDispatcher() {}
@@ -135,7 +134,7 @@ public abstract class GenericAbstractDis
      * @see org.ofbiz.service.LocalDispatcher#schedule(java.lang.String, java.util.Map, long, int, int, int, long)
      */
     public void schedule(String serviceName, Map<String, ? extends Object> context, long startTime, int frequency, int interval, int count, long endTime) throws GenericServiceException {
-        ModelService model = ctx.getModelService(serviceName);
+        ModelService model = getModelService(serviceName);
         schedule(null, serviceName, context, startTime, frequency, interval, count, endTime, model.maxRetry);
     }
 
@@ -180,28 +179,28 @@ public abstract class GenericAbstractDis
      * @see org.ofbiz.service.LocalDispatcher#getJobManager()
      */
     public JobManager getJobManager() {
-        return dispatcher.getJobManager();
+        return globalDispatcher.getJobManager();
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#getJMSListeneFactory()
      */
     public JmsListenerFactory getJMSListeneFactory() {
-        return dispatcher.getJMSListenerFactory();
+        return globalDispatcher.getJMSListenerFactory();
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#getDelegator()
      */
     public Delegator getDelegator() {
-        return dispatcher.getDelegator();
+        return globalDispatcher.getDelegator();
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#getSecurity()
      */
     public Security getSecurity() {
-        return dispatcher.getSecurity();
+        return globalDispatcher.getSecurity();
     }
 
     /**
@@ -212,25 +211,18 @@ public abstract class GenericAbstractDis
     }
 
     /**
-     * @see org.ofbiz.service.LocalDispatcher#getDispatchContext()
-     */
-    public DispatchContext getDispatchContext() {
-        return ctx;
-    }
-
-    /**
      * @see org.ofbiz.service.LocalDispatcher#deregister()
      */
     public void deregister() {
         ServiceContainer.removeFromCache(getName());
-        dispatcher.deregister(this);
+        globalDispatcher.deregister(this);
     }
 
     /**
      * @see org.ofbiz.service.LocalDispatcher#registerCallback(String, GenericServiceCallback)
      */
     public void registerCallback(String serviceName, GenericServiceCallback cb) {
-        dispatcher.registerCallback(serviceName, cb);
+        globalDispatcher.registerCallback(serviceName, cb);
     }
 }
 

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/GenericDispatcherFactory.java Mon Sep  8 06:04:39 2014
@@ -19,16 +19,22 @@
 package org.ofbiz.service;
 
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.Delegator;
+import org.ofbiz.entity.GenericEntityConfException;
+import org.ofbiz.entity.config.model.DelegatorElement;
+import org.ofbiz.entity.config.model.EntityConfig;
 
 /**
  * A default {@link LocalDispatcherFactory} implementation.
  */
 public class GenericDispatcherFactory implements LocalDispatcherFactory {
 
+    public static final String module = GenericDispatcherFactory.class.getName();
     protected static boolean ecasDisabled = false;
 
     @Override
@@ -36,11 +42,25 @@ public class GenericDispatcherFactory im
         if (UtilValidate.isEmpty(name)) {
             throw new IllegalArgumentException("The name of a LocalDispatcher cannot be a null or empty String");
         }
-        // attempts to retrieve an already registered DispatchContext with the name "name"
+        // attempts to retrieve an already registered LocalDispatcher with the name "name"
         LocalDispatcher dispatcher = ServiceDispatcher.getLocalDispatcher(name, delegator);
-        // if not found then create a new GenericDispatcher object; the constructor will also register a new DispatchContext in the ServiceDispatcher with name "dispatcherName"
+        // if not found then create a new GenericDispatcher object
         if (dispatcher == null) {
-            dispatcher = new GenericDispatcher(name, delegator);
+            ServiceDispatcher globalDispatcher = ServiceDispatcher.getInstance(delegator);
+            String modelName = name;
+            if (delegator != null) {
+                DelegatorElement delegatorInfo = null;
+                try {
+                    delegatorInfo = EntityConfig.getInstance().getDelegator(delegator.getDelegatorBaseName());
+                } catch (GenericEntityConfException e) {
+                    Debug.logWarning(e, "Exception thrown while getting delegator config: ", module);
+                }
+                if (delegatorInfo != null) {
+                    modelName = delegatorInfo.getEntityModelReader();
+                }
+            }
+            Map<String, ModelService> serviceMap = globalDispatcher.getGlobalServiceMap(modelName);
+            dispatcher = globalDispatcher.register(new GenericDispatcher(name, globalDispatcher, serviceMap));
         }
         return dispatcher;
     }
@@ -48,23 +68,23 @@ public class GenericDispatcherFactory im
     // The default LocalDispatcher implementation.
     private class GenericDispatcher extends GenericAbstractDispatcher {
 
-        private GenericDispatcher(String name, Delegator delegator) {
+        private final ClassLoader loader;
+        private final Map<String, ModelService> serviceMap;
+
+        private GenericDispatcher(String name, ServiceDispatcher globalDispatcher, Map<String, ModelService> serviceMap) {
             ClassLoader loader;
             try {
                 loader = Thread.currentThread().getContextClassLoader();
             } catch (SecurityException e) {
                 loader = this.getClass().getClassLoader();
             }
+            this.loader = loader;
             this.name = name;
-            this.dispatcher = ServiceDispatcher.getInstance(delegator);
-            /* 
-             * FIXME: "this" reference escape. DispatchContext constructor uses
-             * this object before it is fully constructed.
-             */
-            DispatchContext ctx = new DispatchContext(name, loader, this);
-            this.dispatcher.register(ctx);
-            this.ctx = ctx;
-            if (Debug.verboseOn()) Debug.logVerbose("[GenericDispatcher] : Created Dispatcher for: " + name, module);
+            this.globalDispatcher = globalDispatcher;
+            this.serviceMap = serviceMap;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created Dispatcher for: " + name, module);
+            }
         }
 
         @Override
@@ -83,14 +103,16 @@ public class GenericDispatcherFactory im
         }
 
         @Override
-        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context) throws ServiceValidationException, GenericServiceException {
-            ModelService service = ctx.getModelService(serviceName);
-            return dispatcher.runSync(this.name, service, context);
+        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context)
+                throws ServiceValidationException, GenericServiceException {
+            ModelService service = getModelService(serviceName);
+            return globalDispatcher.runSync(this.name, service, context);
         }
 
         @Override
-        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = ctx.getModelService(serviceName);
+        public Map<String, Object> runSync(String serviceName, Map<String, ? extends Object> context, int transactionTimeout,
+                boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = getModelService(serviceName);
             // clone the model service for updates
             ModelService cloned = new ModelService(service);
             cloned.requireNewTransaction = requireNewTransaction;
@@ -100,23 +122,25 @@ public class GenericDispatcherFactory im
             if (transactionTimeout != -1) {
                 cloned.transactionTimeout = transactionTimeout;
             }
-            return dispatcher.runSync(this.name, cloned, context);
+            return globalDispatcher.runSync(this.name, cloned, context);
         }
 
         @Override
-        public Map<String, Object> runSync(String serviceName, int transactionTimeout, boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public Map<String, Object> runSync(String serviceName, int transactionTimeout, boolean requireNewTransaction,
+                Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             return runSync(serviceName, ServiceUtil.makeContext(context), transactionTimeout, requireNewTransaction);
         }
 
         @Override
         public void runSyncIgnore(String serviceName, Map<String, ? extends Object> context) throws GenericServiceException {
-            ModelService service = ctx.getModelService(serviceName);
-            dispatcher.runSyncIgnore(this.name, service, context);
+            ModelService service = getModelService(serviceName);
+            globalDispatcher.runSyncIgnore(this.name, service, context);
         }
 
         @Override
-        public void runSyncIgnore(String serviceName, Map<String, ? extends Object> context, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = ctx.getModelService(serviceName);
+        public void runSyncIgnore(String serviceName, Map<String, ? extends Object> context, int transactionTimeout,
+                boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = getModelService(serviceName);
             // clone the model service for updates
             ModelService cloned = new ModelService(service);
             cloned.requireNewTransaction = requireNewTransaction;
@@ -126,17 +150,20 @@ public class GenericDispatcherFactory im
             if (transactionTimeout != -1) {
                 cloned.transactionTimeout = transactionTimeout;
             }
-            dispatcher.runSyncIgnore(this.name, cloned, context);
+            globalDispatcher.runSyncIgnore(this.name, cloned, context);
         }
 
         @Override
-        public void runSyncIgnore(String serviceName, int transactionTimeout, boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runSyncIgnore(String serviceName, int transactionTimeout, boolean requireNewTransaction, Object... context)
+                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runSyncIgnore(serviceName, ServiceUtil.makeContext(context), transactionTimeout, requireNewTransaction);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester, boolean persist, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = ctx.getModelService(serviceName);
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester,
+                boolean persist, int transactionTimeout, boolean requireNewTransaction) throws ServiceAuthException,
+                ServiceValidationException, GenericServiceException {
+            ModelService service = getModelService(serviceName);
             // clone the model service for updates
             ModelService cloned = new ModelService(service);
             cloned.requireNewTransaction = requireNewTransaction;
@@ -146,67 +173,104 @@ public class GenericDispatcherFactory im
             if (transactionTimeout != -1) {
                 cloned.transactionTimeout = transactionTimeout;
             }
-            dispatcher.runAsync(this.name, cloned, context, requester, persist);
+            globalDispatcher.runAsync(this.name, cloned, context, requester, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, GenericRequester requester, boolean persist, int transactionTimeout, boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, GenericRequester requester, boolean persist, int transactionTimeout,
+                boolean requireNewTransaction, Object... context) throws ServiceAuthException, ServiceValidationException,
+                GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), requester, persist, transactionTimeout, requireNewTransaction);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = ctx.getModelService(serviceName);
-            dispatcher.runAsync(this.name, service, context, requester, persist);
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester,
+                boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = getModelService(serviceName);
+            globalDispatcher.runAsync(this.name, service, context, requester, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, GenericRequester requester, boolean persist, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, GenericRequester requester, boolean persist, Object... context)
+                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), requester, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, GenericRequester requester)
+                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             runAsync(serviceName, context, requester, true);
         }
 
         @Override
-        public void runAsync(String serviceName, GenericRequester requester, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, GenericRequester requester, Object... context) throws ServiceAuthException,
+                ServiceValidationException, GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), requester);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
-            ModelService service = ctx.getModelService(serviceName);
-            dispatcher.runAsync(this.name, service, context, persist);
+        public void runAsync(String serviceName, Map<String, ? extends Object> context, boolean persist)
+                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+            ModelService service = getModelService(serviceName);
+            globalDispatcher.runAsync(this.name, service, context, persist);
         }
 
         @Override
-        public void runAsync(String serviceName, boolean persist, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, boolean persist, Object... context) throws ServiceAuthException,
+                ServiceValidationException, GenericServiceException {
             runAsync(serviceName, ServiceUtil.makeContext(context), persist);
         }
 
         @Override
-        public void runAsync(String serviceName, Map<String, ? extends Object> context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public void runAsync(String serviceName, Map<String, ? extends Object> context) throws ServiceAuthException,
+                ServiceValidationException, GenericServiceException {
             runAsync(serviceName, context, true);
         }
 
         @Override
-        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context, boolean persist) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context, boolean persist)
+                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             GenericResultWaiter waiter = new GenericResultWaiter();
             this.runAsync(serviceName, context, waiter, persist);
             return waiter;
         }
 
         @Override
-        public GenericResultWaiter runAsyncWait(String serviceName, boolean persist, Object... context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public GenericResultWaiter runAsyncWait(String serviceName, boolean persist, Object... context)
+                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             return runAsyncWait(serviceName, ServiceUtil.makeContext(context), persist);
         }
 
         @Override
-        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context) throws ServiceAuthException, ServiceValidationException, GenericServiceException {
+        public GenericResultWaiter runAsyncWait(String serviceName, Map<String, ? extends Object> context)
+                throws ServiceAuthException, ServiceValidationException, GenericServiceException {
             return runAsyncWait(serviceName, context, true);
         }
-    }
 
+        @Override
+        public DispatchContext getDispatchContext() {
+            return new DispatchContext(this);
+        }
+
+        @Override
+        public Set<String> getAllServiceNames() {
+            Set<String> serviceNames = new TreeSet<String>();
+            serviceNames.addAll(serviceMap.keySet());
+            return serviceNames;
+        }
+
+        @Override
+        public ModelService getModelService(String serviceName) throws GenericServiceException {
+            ModelService modelService = serviceMap.get(serviceName);
+            if (modelService == null) {
+                throw new GenericServiceException("ModelService not found for name: " + serviceName);
+            }
+            return modelService;
+        }
+
+        @Override
+        public ClassLoader getClassLoader() {
+            return loader;
+        }
+    }
 }

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/LocalDispatcher.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/LocalDispatcher.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/LocalDispatcher.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/LocalDispatcher.java Mon Sep  8 06:04:39 2014
@@ -19,6 +19,7 @@
 package org.ofbiz.service;
 
 import java.util.Map;
+import java.util.Set;
 
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.security.Security;
@@ -26,11 +27,11 @@ import org.ofbiz.service.jms.JmsListener
 import org.ofbiz.service.job.JobManager;
 
 /**
- * A local service dispatcher. This is the main API for the service engine.
- * <p>Instances of <code>LocalDispatcher</code> are based on a {@link org.ofbiz.entity.Delegator}
- * instance and an entity model reader name. You can get a <code>LocalDispatcher</code> instance
- * by calling the {@link org.ofbiz.service.ServiceDispatcher#getLocalDispatcher(String, Delegator)}
- * factory method.</p>
+ * A local service dispatcher.
+ * <p> A LocalDispatcher is associated with an application. Applications never talk directly to the ServiceDispatcher.
+ * The LocalDispatcher contains an API for invoking services, which are routed through the ServiceDispatcher.
+ * However, applications may be running in different threads than the actual ServiceDispatcher, so it is left to the
+ * LocalDispatcher to keep a reference to the application's classloader.</p>
  */
 public interface LocalDispatcher {
 
@@ -345,5 +346,11 @@ public interface LocalDispatcher {
      * De-Registers this LocalDispatcher
      */
     void deregister();
+
+    ModelService getModelService(String serviceName) throws GenericServiceException;
+
+    Set<String> getAllServiceNames();
+
+    ClassLoader getClassLoader();
 }
 

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelService.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelService.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelService.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelService.java Mon Sep  8 06:04:39 2014
@@ -1092,9 +1092,9 @@ public class ModelService extends Abstra
 
     /**
      * Run the interface update and inherit all interface parameters
-     * @param dctx The DispatchContext to use for service lookups
+     * @param serviceMap The Map to use for service lookups
      */
-    public synchronized void interfaceUpdate(DispatchContext dctx) throws GenericServiceException {
+    public synchronized void interfaceUpdate(Map<String, ModelService> serviceMap) throws GenericServiceException {
         if (!inheritedParameters) {
             // services w/ engine 'group' auto-implement the grouped services
             if (this.engineName.equals("group") && implServices.size() == 0) {
@@ -1111,13 +1111,15 @@ public class ModelService extends Abstra
             }
 
             // handle interfaces
-            if (UtilValidate.isNotEmpty(implServices) && dctx != null) {
+            if (UtilValidate.isNotEmpty(implServices) && serviceMap != null) {
                 for (ModelServiceIface iface: implServices) {
                     String serviceName = iface.getService();
                     boolean optional = iface.isOptional();
-
-                    ModelService model = dctx.getModelService(serviceName);
+                    ModelService model = serviceMap.get(serviceName);
                     if (model != null) {
+                        if (!model.inheritedParameters()) {
+                            model.interfaceUpdate(serviceMap);
+                        }
                         for (ModelParam newParam: model.contextParamList) {
                             ModelParam existingParam = this.contextInfo.get(newParam.name);
                             if (existingParam != null) {

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelServiceReader.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelServiceReader.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelServiceReader.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ModelServiceReader.java Mon Sep  8 06:04:39 2014
@@ -51,8 +51,6 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
-import freemarker.template.utility.StringUtil;
-
 /**
  * Generic Service - Service Definition Reader
  */
@@ -182,11 +180,11 @@ public class ModelServiceReader implemen
         }
         if (this.isFromURL) {
             utilTimer.timerString("Finished file " + readerURL + " - Total Services: " + i + " FINISHED");
-            Debug.logInfo("Loaded [" + StringUtil.leftPad(Integer.toString(i), 3) + "] Services from " + readerURL, module);
+            Debug.logInfo("Loaded [" + i + "] Services from " + readerURL, module);
         } else {
             utilTimer.timerString("Finished document in " + handler + " - Total Services: " + i + " FINISHED");
             if (Debug.infoOn()) {
-                Debug.logInfo("Loaded [" + StringUtil.leftPad(Integer.toString(i), 3) + "] Services from " + resourceLocation, module);
+                Debug.logInfo("Loaded [" + i + "] Services from " + resourceLocation, module);
             }
         }
         return modelServices;

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ServiceDispatcher.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ServiceDispatcher.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/ServiceDispatcher.java Mon Sep  8 06:04:39 2014
@@ -18,22 +18,30 @@
  *******************************************************************************/
 package org.ofbiz.service;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Future;
 
 import javax.transaction.Transaction;
 
+import org.ofbiz.base.component.ComponentConfig;
+import org.ofbiz.base.concurrent.ExecutionPool;
 import org.ofbiz.base.config.GenericConfigException;
+import org.ofbiz.base.config.MainResourceHandler;
+import org.ofbiz.base.config.ResourceHandler;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralRuntimeException;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilProperties;
 import org.ofbiz.base.util.UtilTimer;
 import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.cache.UtilCache;
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.DelegatorFactory;
 import org.ofbiz.entity.GenericDelegator;
@@ -46,6 +54,7 @@ import org.ofbiz.security.Security;
 import org.ofbiz.security.SecurityConfigurationException;
 import org.ofbiz.security.SecurityFactory;
 import org.ofbiz.service.config.ServiceConfigUtil;
+import org.ofbiz.service.config.model.GlobalServices;
 import org.ofbiz.service.config.model.StartupService;
 import org.ofbiz.service.eca.ServiceEcaRule;
 import org.ofbiz.service.eca.ServiceEcaUtil;
@@ -60,8 +69,12 @@ import org.ofbiz.service.semaphore.Servi
 import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
 
 /**
- * The global service dispatcher. This is the "engine" part of the
- * Service Engine.
+ * The global service dispatcher.
+ * <p>The Service Dispatcher handles dispatching services to the appropriate Service Engine where it is then invoked.
+ * There is exactly one ServiceDispatcher for each Entity Delegator. If there are multiple delegators in an application
+ * there will also be multiple dispatchers. The ServiceDispatcher is accessed via a LocalDispatcher. There can be many
+ * LocalDispatchers associated with a ServiceDispatcher. Each LocalDispatcher is uniquely named and contains its own
+ * list of service definitions.</p>
  */
 public class ServiceDispatcher {
 
@@ -69,6 +82,7 @@ public class ServiceDispatcher {
     public static final int lruLogSize = 200;
     public static final int LOCK_RETRIES = 3;
 
+    private static final UtilCache<String, Map<String, ModelService>> modelServiceMapByModel = UtilCache.createUtilCache("service.ModelServiceMapByModel", 0, 0, false);
     protected static final Map<RunningService, ServiceDispatcher> runLog = new ConcurrentLinkedHashMap.Builder<RunningService, ServiceDispatcher>().maximumWeightedCapacity(lruLogSize).build();
     protected static ConcurrentHashMap<String, ServiceDispatcher> dispatchers = new ConcurrentHashMap<String, ServiceDispatcher>();
     // FIXME: These fields are not thread-safe. They are modified by EntityDataLoadContainer.
@@ -80,7 +94,7 @@ public class ServiceDispatcher {
     protected Delegator delegator = null;
     protected GenericEngineFactory factory = null;
     protected Security security = null;
-    protected Map<String, DispatchContext> localContext = new HashMap<String, DispatchContext>();
+    protected ConcurrentHashMap<String, LocalDispatcher> localDispatchers = new ConcurrentHashMap<String, LocalDispatcher>();
     protected Map<String, List<GenericServiceCallback>> callbacks = new HashMap<String, List<GenericServiceCallback>>();
     protected JobManager jm = null;
     protected JmsListenerFactory jlf = null;
@@ -174,21 +188,25 @@ public class ServiceDispatcher {
     }
 
     /**
-     * Registers the loader with this ServiceDispatcher
-     * @param context the context of the local dispatcher
+     * Registers the LocalDispatcher with this ServiceDispatcher
+     * @param local
      */
-    public void register(DispatchContext context) {
-        if (Debug.infoOn()) Debug.logInfo("Registering dispatcher: " + context.getName(), module);
-        this.localContext.put(context.getName(), context);
+    public LocalDispatcher register(LocalDispatcher local) {
+        if (Debug.infoOn()) {
+            Debug.logInfo("Registering dispatcher: " + local.getName(), module);
+        }
+        localDispatchers.putIfAbsent(local.getName(), local);
+        return localDispatchers.get(local.getName());
     }
+
     /**
      * De-Registers the loader with this ServiceDispatcher
      * @param local the LocalDispatcher to de-register
      */
     public void deregister(LocalDispatcher local) {
         if (Debug.infoOn()) Debug.logInfo("De-Registering dispatcher: " + local.getName(), module);
-        localContext.remove(local.getName());
-        if (localContext.size() == 0) {
+        localDispatchers.remove(local.getName());
+        if (localDispatchers.size() == 0) {
             try {
                  this.shutdown();
              } catch (GenericServiceException e) {
@@ -255,7 +273,7 @@ public class ServiceDispatcher {
         Map<String, List<ServiceEcaRule>> eventMap = null;
         Map<String, Object> ecaContext = null;
         RunningService rs = null;
-        DispatchContext ctx = localContext.get(localName);
+        DispatchContext ctx = getLocalContext(localName);
         GenericEngine engine = null;
         Transaction parentTransaction = null;
         boolean isFailure = false;
@@ -641,7 +659,7 @@ public class ServiceDispatcher {
         Locale locale = this.checkLocale(context);
 
         // setup the engine and context
-        DispatchContext ctx = localContext.get(localName);
+        DispatchContext ctx = getLocalContext(localName);
         GenericEngine engine = this.getGenericEngine(service.engineName);
 
         // for isolated transactions
@@ -822,7 +840,11 @@ public class ServiceDispatcher {
      * @param name of the context to find.
      */
     public DispatchContext getLocalContext(String name) {
-        return localContext.get(name);
+        LocalDispatcher local = localDispatchers.get(name);
+        if (local != null) {
+            return new DispatchContext(local);
+        }
+        return null;
     }
 
     /**
@@ -831,7 +853,7 @@ public class ServiceDispatcher {
      * @return LocalDispatcher matching the loader name
      */
     public LocalDispatcher getLocalDispatcher(String name) {
-        return localContext.get(name).getDispatcher();
+        return localDispatchers.get(name);
     }
 
     /**
@@ -840,7 +862,7 @@ public class ServiceDispatcher {
      * @return true if the local context is found in this dispatcher.
      */
     public boolean containsContext(String name) {
-        return localContext.containsKey(name);
+        return localDispatchers.containsKey(name);
     }
 
     protected void shutdown() throws GenericServiceException {
@@ -1053,4 +1075,58 @@ public class ServiceDispatcher {
         return runLog;
     }
 
+    private Callable<Map<String, ModelService>> createServiceReaderCallable(final ResourceHandler handler) {
+        return new Callable<Map<String, ModelService>>() {
+            public Map<String, ModelService> call() throws Exception {
+                return ModelServiceReader.getModelServiceMap(handler, delegator);
+            }
+        };
+    }
+
+    Map<String, ModelService> getGlobalServiceMap(String model) {
+        Map<String, ModelService> serviceMap = modelServiceMapByModel.get(model);
+        if (serviceMap == null) {
+            serviceMap = new HashMap<String, ModelService>();
+            List<Future<Map<String, ModelService>>> futures = new LinkedList<Future<Map<String, ModelService>>>();
+            List<GlobalServices> globalServicesList = null;
+            try {
+                globalServicesList = ServiceConfigUtil.getServiceEngine().getGlobalServices();
+            } catch (GenericConfigException e) {
+                // FIXME: Refactor API so exceptions can be thrown and caught.
+                Debug.logError(e, module);
+                throw new RuntimeException(e.getMessage());
+            }
+            for (GlobalServices globalServices : globalServicesList) {
+                ResourceHandler handler = new MainResourceHandler(ServiceConfigUtil.SERVICE_ENGINE_XML_FILENAME, globalServices.getLoader(), globalServices.getLocation());
+                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(handler)));
+            }
+
+            // get all of the component resource model stuff, ie specified in each ofbiz-component.xml file
+            for (ComponentConfig.ServiceResourceInfo componentResourceInfo: ComponentConfig.getAllServiceResourceInfos("model")) {
+                futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(createServiceReaderCallable(componentResourceInfo.createResourceHandler())));
+            }
+            for (Map<String, ModelService> servicesMap: ExecutionPool.getAllFutures(futures)) {
+                if (servicesMap != null) {
+                    serviceMap.putAll(servicesMap);
+                }
+            }
+            for (ModelService modelService : serviceMap.values()) {
+                if (!modelService.inheritedParameters()) {
+                    try {
+                        modelService.interfaceUpdate(serviceMap);
+                    } catch (GenericServiceException e) {
+                        Debug.logError(e, module);
+                        throw new RuntimeException(e.getMessage());
+                    }
+                }
+            }
+            serviceMap = Collections.unmodifiableMap(serviceMap);
+            Map<String, ModelService> cachedServiceMap = modelServiceMapByModel.putIfAbsentAndGet(model, serviceMap);
+            if (cachedServiceMap == serviceMap) { // same object: this means that the object created by this thread was actually added to the cache
+                ServiceEcaUtil.reloadConfig();
+            }
+        }
+        return serviceMap;
+    }
+
 }

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/eca/ServiceEcaUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/eca/ServiceEcaUtil.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/eca/ServiceEcaUtil.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/eca/ServiceEcaUtil.java Mon Sep  8 06:04:39 2014
@@ -43,8 +43,6 @@ import org.ofbiz.service.config.ServiceC
 import org.ofbiz.service.config.model.ServiceEcas;
 import org.w3c.dom.Element;
 
-import freemarker.template.utility.StringUtil;
-
 /**
  * ServiceEcaUtil
  */
@@ -123,7 +121,7 @@ public class ServiceEcaUtil {
             handlerRules.add(new ServiceEcaRule(e, resourceLocation));
         }
         if (Debug.infoOn()) {
-            Debug.logInfo("Loaded [" + StringUtil.leftPad(Integer.toString(handlerRules.size()), 3) + "] Service ECA Rules from " + resourceLocation, module);
+            Debug.logInfo("Loaded [" + handlerRules.size() + "] Service ECA Rules from " + resourceLocation, module);
         }
         return handlerRules;
     }

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/group/ServiceGroupReader.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/group/ServiceGroupReader.java?rev=1623295&r1=1623294&r2=1623295&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/group/ServiceGroupReader.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/service/src/org/ofbiz/service/group/ServiceGroupReader.java Mon Sep  8 06:04:39 2014
@@ -33,8 +33,6 @@ import org.ofbiz.service.config.ServiceC
 import org.ofbiz.service.config.model.ServiceGroups;
 import org.w3c.dom.Element;
 
-import freemarker.template.utility.StringUtil;
-
 /**
  * ServiceGroupReader.java
  */
@@ -88,7 +86,7 @@ public class ServiceGroupReader {
             } catch (GenericConfigException e) {
                 Debug.logError(e, "Could not get resource URL", module);
             }
-            Debug.logInfo("Loaded [" + StringUtil.leftPad(Integer.toString(numDefs), 3) + "] Group definitions from " + resourceLocation, module);
+            Debug.logInfo("Loaded [" + numDefs + "] Group definitions from " + resourceLocation, module);
         }
     }