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=1621696&r1=1621695&r2=1621696&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 1 07:29:23 2014 @@ -22,14 +22,12 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.Hashtable; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.transaction.Transaction; import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.UtilProperties; -import org.ofbiz.entity.GenericDelegator; import org.ofbiz.entity.GenericEntityException; import org.ofbiz.entity.datasource.GenericHelperInfo; import org.ofbiz.entity.model.ModelEntity; @@ -40,20 +38,18 @@ import org.ofbiz.entity.transaction.Tran /** * Sequence Utility to get unique sequences from named sequence banks - * Uses a collision detection approach to safely get unique sequenced ids in banks from the database */ public class SequenceUtil { public static final String module = SequenceUtil.class.getName(); - private final Map<String, SequenceBank> sequences = new Hashtable<String, SequenceBank>(); + private final ConcurrentMap<String, SequenceBank> sequences = new ConcurrentHashMap<String, SequenceBank>(); private final GenericHelperInfo helperInfo; private final String tableName; private final String nameColName; private final String idColName; - private final boolean clustered; - public SequenceUtil(GenericDelegator delegator, GenericHelperInfo helperInfo, ModelEntity seqEntity, String nameFieldName, String idFieldName) { + public SequenceUtil(GenericHelperInfo helperInfo, ModelEntity seqEntity, String nameFieldName, String idFieldName) { this.helperInfo = helperInfo; if (seqEntity == null) { throw new IllegalArgumentException("The sequence model entity was null but is required."); @@ -73,7 +69,6 @@ public class SequenceUtil { throw new IllegalArgumentException("Could not find the field definition for the sequence id field " + idFieldName); } this.idColName = idField.getColName(); - clustered = delegator.useDistributedCacheClear() || "Y".equals(UtilProperties.getPropertyValue("general.properties", "clustered")); } public Long getNextSeqId(String seqName, long staggerMax, ModelEntity seqModelEntity) { @@ -95,18 +90,14 @@ public class SequenceUtil { SequenceBank bank = sequences.get(seqName); if (bank == null) { - synchronized(this) { - bank = sequences.get(seqName); - if (bank == null) { - long bankSize = SequenceBank.defaultBankSize; - if (seqModelEntity != null && seqModelEntity.getSequenceBankSize() != null) { - bankSize = seqModelEntity.getSequenceBankSize().longValue(); - if (bankSize > SequenceBank.maxBankSize) bankSize = SequenceBank.maxBankSize; - } - bank = new SequenceBank(seqName, bankSize); - sequences.put(seqName, bank); - } + long bankSize = SequenceBank.defaultBankSize; + if (seqModelEntity != null && seqModelEntity.getSequenceBankSize() != null) { + bankSize = seqModelEntity.getSequenceBankSize().longValue(); + if (bankSize > SequenceBank.maxBankSize) bankSize = SequenceBank.maxBankSize; } + bank = new SequenceBank(seqName, bankSize); + SequenceBank bankFromCache = sequences.putIfAbsent(seqName, bank); + bank = bankFromCache != null ? bankFromCache : bank; } return bank; @@ -116,55 +107,55 @@ public class SequenceUtil { public static final long defaultBankSize = 10; public static final long maxBankSize = 5000; public static final long startSeqId = 10000; - public static final long minWaitMillis = 5; - public static final long maxWaitMillis = 50; - public static final int maxTries = 5; - private long curSeqId; - private long maxSeqId; private final String seqName; private final long bankSize; + private final String updateForLockStatement; + private final String selectSequenceStatement; + + private long curSeqId; + private long maxSeqId; private SequenceBank(String seqName, long bankSize) { this.seqName = seqName; curSeqId = 0; maxSeqId = 0; this.bankSize = bankSize; - fillBank(1); + updateForLockStatement = "UPDATE " + SequenceUtil.this.tableName + " SET " + SequenceUtil.this.idColName + "=" + SequenceUtil.this.idColName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'"; + selectSequenceStatement = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'"; } - private synchronized Long getNextSeqId(long staggerMax) { + private Long getNextSeqId(long staggerMax) { long stagger = 1; if (staggerMax > 1) { - stagger = Math.round(Math.random() * staggerMax); + stagger = (long)Math.ceil(Math.random() * staggerMax); if (stagger == 0) stagger = 1; } - - if ((curSeqId + stagger) <= maxSeqId) { - Long retSeqId = Long.valueOf(curSeqId); - curSeqId += stagger; - return retSeqId; - } else { - fillBank(stagger); + synchronized (this) { if ((curSeqId + stagger) <= maxSeqId) { - Long retSeqId = Long.valueOf(curSeqId); + long retSeqId = curSeqId; curSeqId += stagger; return retSeqId; } else { - Debug.logError("[SequenceUtil.SequenceBank.getNextSeqId] Fill bank failed, returning null", module); - return null; + fillBank(stagger); + if ((curSeqId + stagger) <= maxSeqId) { + long retSeqId = curSeqId; + curSeqId += stagger; + return retSeqId; + } else { + Debug.logError("Fill bank failed, returning null", module); + return null; + } } } } - private void refresh(long staggerMax) { + private synchronized void refresh(long staggerMax) { this.curSeqId = this.maxSeqId; this.fillBank(staggerMax); } - private synchronized void fillBank(long stagger) { - //Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Starting fillBank Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module); - + private void fillBank(long stagger) { // no need to get a new bank, SeqIds available if ((curSeqId + stagger) <= maxSeqId) return; @@ -176,178 +167,117 @@ public class SequenceUtil { if (bankSize > maxBankSize) bankSize = maxBankSize; - long val1 = 0; - long val2 = 0; + Transaction suspendedTransaction = null; + try { + suspendedTransaction = TransactionUtil.suspend(); + + boolean beganTransaction = false; + try { + beganTransaction = TransactionUtil.begin(); + + Connection connection = null; + Statement stmt = null; + ResultSet rs = null; - // NOTE: the fancy ethernet type stuff is for the case where transactions not available, or something funny happens with really sensitive timing (between first select and update, for example) - int numTries = 0; - - while (val1 + bankSize != val2) { - if (Debug.verboseOn()) Debug.logVerbose("[SequenceUtil.SequenceBank.fillBank] Trying to get a bank of sequenced ids for " + - this.seqName + "; start of loop val1=" + val1 + ", val2=" + val2 + ", bankSize=" + bankSize, module); - - // not sure if this synchronized block is totally necessary, the method is synchronized but it does do a wait/sleep - // outside of this block, and this is the really sensitive block, so making sure it is isolated; there is some overhead - // to this, but very bad things can happen if we try to do too many of these at once for a single sequencer - synchronized (this) { - Transaction suspendedTransaction = null; try { - //if we can suspend the transaction, we'll try to do this in a local manual transaction - suspendedTransaction = TransactionUtil.suspend(); - - boolean beganTransaction = false; - try { - beganTransaction = TransactionUtil.begin(); - - Connection connection = null; - Statement stmt = null; - ResultSet rs = null; - - try { - connection = TransactionFactoryLoader.getInstance().getConnection(SequenceUtil.this.helperInfo); - } catch (SQLException sqle) { - Debug.logWarning("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database... Error was:" + sqle.toString(), module); - throw sqle; - } catch (GenericEntityException e) { - Debug.logWarning("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database... Error was: " + e.toString(), module); - throw e; - } - - if (connection == null) { - throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database, connection was null..."); - } - - String sql = null; - - try { - // we shouldn't need this, and some TX managers complain about it, so not including it: connection.setAutoCommit(false); - - stmt = connection.createStatement(); - if (clustered) { - sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'" + " FOR UPDATE"; - } else { - sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'"; - } - rs = stmt.executeQuery(sql); - boolean gotVal1 = false; - if (rs.next()) { - val1 = rs.getLong(SequenceUtil.this.idColName); - gotVal1 = true; - } - rs.close(); - - if (!gotVal1) { - Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] first select failed: will try to add new row, result set was empty for sequence [" + seqName + "] \nUsed SQL: " + sql + " \n Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module); - sql = "INSERT INTO " + SequenceUtil.this.tableName + " (" + SequenceUtil.this.nameColName + ", " + SequenceUtil.this.idColName + ") VALUES ('" + this.seqName + "', " + startSeqId + ")"; - if (stmt.executeUpdate(sql) <= 0) { - throw new GenericEntityException("No rows changed when trying insert new sequence row with this SQL: " + sql); - } - continue; - } - - 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("[SequenceUtil.SequenceBank.fillBank] update failed, no rows changes for seqName: " + seqName); - } - if (clustered) { - sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'" + " FOR UPDATE"; - - } else { - sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'"; - } - rs = stmt.executeQuery(sql); - boolean gotVal2 = false; - if (rs.next()) { - val2 = rs.getLong(SequenceUtil.this.idColName); - gotVal2 = true; - } - - rs.close(); + connection = TransactionFactoryLoader.getInstance().getConnection(SequenceUtil.this.helperInfo); + } catch (SQLException sqle) { + Debug.logWarning("Unable to esablish a connection with the database. Error was:" + sqle.toString(), module); + throw sqle; + } catch (GenericEntityException e) { + Debug.logWarning("Unable to esablish a connection with the database. Error was: " + e.toString(), module); + throw e; + } + if (connection == null) { + throw new GenericEntityException("Unable to esablish a connection with the database, connection was null..."); + } - if (!gotVal2) { - throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank] second select failed: aborting, result set was empty for sequence: " + seqName); - } + String sql = null; + try { + stmt = connection.createStatement(); - // got val1 and val2 at this point, if we don't have the right difference between them, force a rollback (with - //setRollbackOnly and NOT with an exception because we don't want to break from the loop, just err out and - //continue), then flow out to allow the wait and loop thing to happen - if (val1 + bankSize != val2) { - TransactionUtil.setRollbackOnly("Forcing transaction rollback in sequence increment because we didn't get a clean update, ie a conflict was found, so not saving the results", null); - } - } catch (SQLException sqle) { - Debug.logWarning(sqle, "[SequenceUtil.SequenceBank.fillBank] SQL Exception while executing the following:\n" + sql + "\nError was:" + sqle.getMessage(), module); - throw sqle; - } finally { - try { - if (stmt != null) stmt.close(); - } catch (SQLException sqle) { - Debug.logWarning(sqle, "Error closing statement in sequence util", module); - } - try { - if (connection != null) connection.close(); - } catch (SQLException sqle) { - Debug.logWarning(sqle, "Error closing connection in sequence util", module); + // 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); + sql = "INSERT INTO " + SequenceUtil.this.tableName + " (" + SequenceUtil.this.nameColName + ", " + SequenceUtil.this.idColName + ") VALUES ('" + this.seqName + "', " + startSeqId + ")"; + if (stmt.executeUpdate(sql) <= 0) { + // 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); } } - } catch (Exception e) { - String errMsg = "General error in getting a sequenced ID"; - Debug.logError(e, errMsg, module); - try { - TransactionUtil.rollback(beganTransaction, errMsg, e); - } catch (GenericTransactionException gte2) { - Debug.logError(gte2, "Unable to rollback transaction", module); - } - - // error, break out of the loop to not try to continue forever - break; - } finally { - try { - TransactionUtil.commit(beganTransaction); - } catch (GenericTransactionException gte) { - Debug.logError(gte, "Unable to commit sequence increment transaction, continuing anyway though", module); - } } - } catch (GenericTransactionException e) { - Debug.logError(e, "System Error suspending transaction in sequence util", module); + // select the record (now locked) to get the curSeqId + rs = stmt.executeQuery(selectSequenceStatement); + boolean gotVal = false; + if (rs.next()) { + curSeqId = rs.getLong(SequenceUtil.this.idColName); + gotVal = true; + } + rs.close(); + if (!gotVal) { + throw new GenericEntityException("Failed to find the sequence record: " + sql); + } + // 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); + } + + TransactionUtil.commit(beganTransaction); + + } catch (SQLException sqle) { + Debug.logWarning(sqle, "SQL Exception:" + sqle.getMessage(), module); + throw sqle; } finally { - if (suspendedTransaction != null) { - try { - TransactionUtil.resume(suspendedTransaction); - } catch (GenericTransactionException e) { - Debug.logError(e, "Error resuming suspended transaction in sequence util", module); - } + try { + if (stmt != null) stmt.close(); + } catch (SQLException sqle) { + Debug.logWarning(sqle, "Error closing statement in sequence util", module); + } + try { + if (connection != null) connection.close(); + } catch (SQLException sqle) { + Debug.logWarning(sqle, "Error closing connection in sequence util", module); } } - } - - if (val1 + bankSize != val2) { - if (numTries >= maxTries) { - String errMsg = "[SequenceUtil.SequenceBank.fillBank] maxTries (" + maxTries + ") reached for seqName [" + this.seqName + "], giving up."; - Debug.logError(errMsg, module); - return; + } catch (Exception e) { + // reset the sequence fields and return (note: it would be better to throw an exception) + curSeqId = 0; + maxSeqId = 0; + String errMsg = "General error in getting a sequenced ID"; + Debug.logError(e, errMsg, module); + try { + TransactionUtil.rollback(beganTransaction, errMsg, e); + } catch (GenericTransactionException gte2) { + Debug.logError(gte2, "Unable to rollback transaction", module); } - - // collision happened, wait a bounded random amount of time then continue - long waitTime = (long) (Math.random() * (maxWaitMillis - minWaitMillis) + minWaitMillis); - - Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Collision found for seqName [" + seqName + "], val1=" + val1 + ", val2=" + val2 + ", val1+bankSize=" + (val1 + bankSize) + ", bankSize=" + bankSize + ", waitTime=" + waitTime, module); - + return; + } + } catch (GenericTransactionException e) { + Debug.logError(e, "System Error suspending transaction in sequence util", module); + // reset the sequence fields and return (note: it would be better to throw an exception) + curSeqId = 0; + maxSeqId = 0; + return; + } finally { + if (suspendedTransaction != null) { try { - // using the Thread.sleep to more reliably lock this thread: this.wait(waitTime); - java.lang.Thread.sleep(waitTime); - } catch (Exception e) { - Debug.logWarning(e, "Error waiting in sequence util", module); + TransactionUtil.resume(suspendedTransaction); + } catch (GenericTransactionException e) { + Debug.logError(e, "Error resuming suspended transaction in sequence util", module); + // reset the sequence fields and return (note: it would be better to throw an exception) + curSeqId = 0; + maxSeqId = 0; return; } } - - numTries++; } - curSeqId = val1; - maxSeqId = val2; + maxSeqId = curSeqId + bankSize; if (Debug.infoOn()) Debug.logInfo("Got bank of sequenced IDs for [" + this.seqName + "]; curSeqId=" + curSeqId + ", maxSeqId=" + maxSeqId + ", bankSize=" + bankSize, module); - //Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Ending fillBank Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module); } } } + Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/config/EntityExtUiLabels.xml URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/config/EntityExtUiLabels.xml?rev=1621696&r1=1621695&r2=1621696&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/config/EntityExtUiLabels.xml (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/entityext/config/EntityExtUiLabels.xml Mon Sep 1 07:29:23 2014 @@ -24,119 +24,139 @@ <value xml:lang="fr">Impossible d'effectuer la synchro (push) avec un configuration en mode esclave seulement (pull only).</value> <value xml:lang="it">Non è possibile fare Entity Sync Push perchè entitySyncId [] è impostato in Pull Only.</value> <value xml:lang="zh">æ æ³å®ç°å®ä½åæ¥æ¨éå 为å®ä½åæ¥æ è¯ï¼entitySyncId []ï¼è¢«è®¾ç½®ä¸ºäºåªè½æåã</value> + <value xml:lang="zh_TW">ç¡æ³é²è¡åé«åæ¥æ¨éå çºåé«åæ¥ä»£èï¼entitySyncId []ï¼è¢«è¨å®çº Pull Onlyã</value> </property> <property key="EntityExtCannotFindDelegator"> <value xml:lang="en">Could not find delegator with specified name ${overrideDelegatorName}</value> <value xml:lang="fr">Le delegateur avec le nom ${overrideDelegatorName} n'a pu être trouvé</value> <value xml:lang="it">Could not find delegator with specified name ${overrideDelegatorName}</value> <value xml:lang="zh">æ æ³æ¾å°å称为${overrideDelegatorName}ç代ç</value> + <value xml:lang="zh_TW">ç¡æ³æ¾å°å稱çº${overrideDelegatorName}ç代ç</value> </property> <property key="EntityExtEntitySyncXMLDocumentIsNotValid"> <value xml:lang="en">EntitySync XML document ${fileName} is not valid!</value> <value xml:lang="fr">L'EntitySync XML document ${fileName} n'est pas valide !</value> <value xml:lang="it">EntitySync XML documento ${fileName} non è valido!</value> <value xml:lang="zh">å®ä½åæ¥ï¼EntitySyncï¼XMLææ¡£${fileName}æ æï¼</value> + <value xml:lang="zh_TW">åä½åæ¥ï¼EntitySyncï¼XMLæä»¶${fileName}ç¡æï¼</value> </property> <property key="EntityExtErrorCallingRemotePull"> <value xml:lang="en">Error calling remote pull and report EntitySync service with name: ${remotePullAndReportEntitySyncDataName}</value> <value xml:lang="fr">Erreur lors de l'appel de l'esclave (remote pull) et de son rapport sur le service nommé : ${remotePullAndReportEntitySyncDataName}</value> <value xml:lang="it">Errore durante la chiamata del pull remoto e report EntitySync servizio con il nome: ${remotePullAndReportEntitySyncDataName}</value> <value xml:lang="zh">è°ç¨è¿ç¨æååæ¥è¡¨çå®ä½åæ¥ï¼EntitySyncï¼æå¡æ¶åºéï¼æå¡åç§°ï¼${remotePullAndReportEntitySyncDataName}</value> + <value xml:lang="zh_TW">å¼å«é ç¨æååå ±è¡¨çåä½åæ¥ï¼EntitySyncï¼æåæåºé¯ï¼æåå稱ï¼${remotePullAndReportEntitySyncDataName}</value> </property> <property key="EntityExtErrorCallingService"> <value xml:lang="en">Error calling service to store data locally</value> <value xml:lang="fr">Erreur d'appel du service de mise à jour des données locales</value> <value xml:lang="it">Errore durante la chiamata del servizio di registrazione locale dei dati</value> <value xml:lang="zh">è°ç¨æå¡æ¥æ¬å°å卿°æ®æ¶åºé</value> + <value xml:lang="zh_TW">å¼å«æå便¬å°åå²è³ææåºé¯</value> </property> <property key="EntityExtErrorCleaningEntitySyncRemove"> <value xml:lang="en">Error cleaning out EntitySyncRemove info: ${errorString}</value> <value xml:lang="fr">Erreur lors du nettoyage des EntitySyncRemove, plus d'informations : ${errorString}</value> <value xml:lang="it">Error cleaning out EntitySyncRemove info: ${errorString}</value> <value xml:lang="zh">æ¸ é¤å®ä½åæ¥å é¤ï¼EntitySyncRemoveï¼ä¿¡æ¯æ¶åºéï¼${errorString}</value> + <value xml:lang="zh_TW">æ¸ é¤åé«åæ¥å é¤ï¼EntitySyncRemoveï¼è¨æ¯æåºé¯ï¼${errorString}</value> </property> <property key="EntityExtErrorGettingListOfEntityInGroup"> <value xml:lang="en">Error getting list of entities in group: ${errorString}</value> <value xml:lang="fr">Erreur lors de la récupération des entités du group : ${errorString}</value> <value xml:lang="it">Errore ad ottenere la lista delle entità nel gruppo: ${errorString}</value> <value xml:lang="zh">è·ååç»ä¸çå®ä½å表æ¶åºéï¼${errorString}</value> + <value xml:lang="zh_TW">åå¾åç»ä¸çåé«å表æåºé¯ï¼${errorString}</value> </property> <property key="EntityExtErrorUnwrappingRecords"> <value xml:lang="en">Error unwrapping ByteWrapper records: ${errorString}</value> <value xml:lang="fr">Erreur lors de l"ouverture du flux des enregistrements : ${errorString}</value> <value xml:lang="it">Errore unwrapping ByteWrapper records: ${errorString}</value> <value xml:lang="zh">è§£æByteWrapperè®°å½æ¶åºéï¼${errorString}</value> + <value xml:lang="zh_TW">è§£æByteWrapperè¨éæåºé¯ï¼${errorString}</value> </property> <property key="EntityExtErrorSavingEntitySyncData"> <value xml:lang="en">Error saving Entity Sync Data for entitySyncId ${entitySyncId}: ${errorString}</value> <value xml:lang="fr">Erreur lors de la synchro de donnée pour la référence ${entitySyncId}: ${errorString}</value> <value xml:lang="it">Errore durante il salvataggio Entity Sync Data per entitySyncId ${entitySyncId}: ${errorString}</value> <value xml:lang="zh">为å®ä½åæ¥æ è¯ï¼entitySyncIdï¼${entitySyncId}ä¿åå®ä½åæ¥æ°æ®æ¶åºéï¼${errorString}</value> + <value xml:lang="zh_TW">çºåé«åæ¥ä»£èï¼entitySyncIdï¼${entitySyncId}ä¿ååé«åæ¥è³ææåºé¯ï¼${errorString}</value> </property> <property key="EntityExtExceptionSavingEntitySyncData"> <value xml:lang="en">Exception saving Entity Sync Data for entitySyncId ${entitySyncId}: ${errorString}</value> <value xml:lang="fr">Exception lors de l'enregistrement de la synchro de donnée pour la référence ${entitySyncId}: ${errorString}</value> <value xml:lang="it">Eccezione durante il salvataggio Entity Sync Data per entitySyncId ${entitySyncId}: ${errorString}</value> <value xml:lang="zh">为å®ä½åæ¥æ è¯ï¼entitySyncIdï¼${entitySyncId}ä¿åå®ä½åæ¥æ°æ®æ¶åºç°æå¤ï¼${errorString}</value> + <value xml:lang="zh_TW">çºåé«åæ¥ä»£èï¼entitySyncIdï¼${entitySyncId}ä¿ååé«åæ¥è³ææåºç¾ç°å¸¸ï¼${errorString}</value> </property> <property key="EntityExtFileNotFound"> <value xml:lang="en">File not found: ${fileName}</value> <value xml:lang="fr">Fichier ${fileName} non trouvé</value> <value xml:lang="it">File non trovato: ${fileName}</value> <value xml:lang="zh">æ²¡ææ¾å°æä»¶ï¼${fileName}</value> + <value xml:lang="zh_TW">æ²¡ææ¾å°æä»¶ï¼${fileName}</value> </property> <property key="EntityExtNoFileAvailableInTheRootDirectory"> <value xml:lang="en">No files available for reading in this root directory: ${rootDirectory}</value> <value xml:lang="fr">Aucun fichier disponible pour la lecture dans le répertoire ${rootDirectory}</value> <value xml:lang="it">Nessun file disponibile da leggere nella directory principale: ${rootDirectory}</value> <value xml:lang="zh">è¿ä¸ªæ ¹ç®å½ä¸æ²¡æå¯è¯»çæä»¶ï¼${rootDirectory}</value> + <value xml:lang="zh_TW">éåæ ¹ç®é䏿²¡æå¯è®çæä»¶ï¼${rootDirectory}</value> </property> <property key="EntityExtOfflineXMLFileNotFound"> <value xml:lang="en">Offline EntitySync XML file not found (${fileName})</value> <value xml:lang="fr">Le fichier hors ligne (${fileName}) n'a pas été trouvé</value> <value xml:lang="it">File Offline EntitySync XML non trovato (${fileName})</value> <value xml:lang="zh">æ²¡ææ¾å°ç¦»çº¿å®ä½åæ¥ï¼EntitySyncï¼XMLæä»¶ï¼${fileName}ï¼</value> + <value xml:lang="zh_TW">æ²¡ææ¾å°é¢ç·åé«åæ¥ï¼EntitySyncï¼XMLæä»¶ï¼${fileName}ï¼</value> </property> <property key="EntityExtProblemReadingFile"> <value xml:lang="en">Problem reading file: ${fileName}</value> <value xml:lang="fr">Problème lors de la lecture du fichier ${fileName}</value> <value xml:lang="it">Problema durante la lettura del file: ${fileName}</value> <value xml:lang="zh">读æä»¶æ¶åºé®é¢ï¼${fileName}</value> + <value xml:lang="zh_TW">è®æä»¶æåºåé¡ï¼${fileName}</value> </property> <property key="EntityExtRootDirectoryDoesNotExists"> <value xml:lang="en">Root directory does not exist or is not readable.</value> <value xml:lang="fr">Le répertoire racine n'existe pas ou n'est pas lisible</value> <value xml:lang="it">Directory principale non esiste o non è leggibile.</value> <value xml:lang="zh">æ ¹ç®å½ä¸å卿ä¸å¯è¯»ã</value> + <value xml:lang="zh_TW">æ ¹ç®éä¸å卿ä¸å¯è®ã</value> </property> <property key="EntityExtServicePermissionNotGranted"> <value xml:lang="en">You do not have permission to run this service.</value> <value xml:lang="fr">Vous n'avez pas la permission d'exécuter ce service</value> <value xml:lang="it">Tu non hai il permesso di eseguire questo servizio.</value> <value xml:lang="zh">ä½ æ²¡ææéè¿è¡è¿ä¸ªæå¡ã</value> + <value xml:lang="zh_TW">ä½ æ²¡ææ¬éå·è¡éåæåã</value> </property> <property key="EntityExtThisServiceIsNotYetImplemented"> <value xml:lang="en">This service is not implemented yet.</value> <value xml:lang="fr">Ce service n'est pas implémenté actuellement</value> <value xml:lang="it">Questo servizio non è ancora implementato.</value> <value xml:lang="zh">è¿ä¸ªæå¡å°æªå®ç°ã</value> + <value xml:lang="zh_TW">éåæåå°æªå¯¦ä½ã</value> </property> <property key="EntityExtUnableToLoadXMLDocument"> <value xml:lang="en">Unable to load EntitySync XML ${entitySyncId} - Problem at '${startTime}' Error: ${errorString}</value> <value xml:lang="fr">Impossible de charger l'EntitySync XML ${entitySyncId} - Problème à '${startTime}' , avec l'erreur suivante : ${errorString}</value> <value xml:lang="it">Non è possibile caricare il EntitySync XML ${entitySyncId} - Problema alle '${startTime}' Errore: ${errorString}</value> <value xml:lang="zh">æ æ³è½½å ¥å®ä½åæ¥ï¼EntitySyncï¼XML ${entitySyncId} - é®é¢åçå¨'${startTime}'ï¼é误ï¼${errorString}</value> + <value xml:lang="zh_TW">ç¡æ³è¼å ¥åé«åæ¥ï¼EntitySyncï¼XML ${entitySyncId} - åé¡ç¼çå¨'${startTime}'ï¼é¯èª¤ï¼${errorString}</value> </property> <property key="EntityExtUnableToLocateRootDirectory"> <value xml:lang="en">Unable to locate root directory ${rootDirectory}</value> <value xml:lang="fr">Impossible de localiser le répertoire racine ${rootDirectory}</value> <value xml:lang="it">Non è possibile localizzare la directory principale ${rootDirectory}</value> <value xml:lang="zh">æ æ³å®ä½æ ¹ç®å½${rootDirectory}</value> + <value xml:lang="zh_TW">ç¡æ³å®ä½æ ¹ç®é${rootDirectory}</value> </property> <property key="EntityExtUnableToLocateRootDirectoryURI"> <value xml:lang="en">Unable to get root directory URI</value> <value xml:lang="fr">Impossible de récupérer le répertoire racine</value> <value xml:lang="it">Non è possibile localizzare la directory principale URI</value> <value xml:lang="zh">ä¸è½å¾å°æ ¹ç®å½URI</value> + <value xml:lang="zh_TW">ä¸è½å徿 ¹ç®éURI</value> </property> </resource> Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/DefaultMessages.xml URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/DefaultMessages.xml?rev=1621696&r1=1621695&r2=1621696&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/DefaultMessages.xml (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/DefaultMessages.xml Mon Sep 1 07:29:23 2014 @@ -26,6 +26,7 @@ <value xml:lang="ja">ã¨ã©ã¼:</value> <value xml:lang="nl">Fout: </value> <value xml:lang="zh">é误ï¼</value> + <value xml:lang="zh_TW">é¯èª¤ï¼</value> </property> <property key="check.error.suffix"> <value xml:lang="en"> </value> @@ -58,6 +59,7 @@ <value xml:lang="ja">ã¨ã©ã¼:</value> <value xml:lang="nl">Fout: </value> <value xml:lang="zh">é误ï¼</value> + <value xml:lang="zh_TW">é¯èª¤ï¼</value> </property> <property key="service.error.suffix"> <value xml:lang="en"> </value> Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/MiniLangErrorUiLabels.xml URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/MiniLangErrorUiLabels.xml?rev=1621696&r1=1621695&r2=1621696&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/MiniLangErrorUiLabels.xml (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/config/MiniLangErrorUiLabels.xml Mon Sep 1 07:29:23 2014 @@ -43,13 +43,14 @@ <value xml:lang="ru">ÐÑибка вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ simple-method</value> <value xml:lang="th">Error : à¸à¸´à¸à¸à¸¥à¸²à¸ ! à¹à¸à¸à¸²à¸£à¸£à¸±à¸ simple-method</value> <value xml:lang="zh">è¿è¡è¿ä¸ªç®åæ¹æ³æ¶åºé</value> - <value xml:lang="zh_TW">éè¡éåç°¡å®æ¹æ³æåºé¯</value> + <value xml:lang="zh_TW">å·è¡éåç°¡å®æ¹æ³æåºé¯</value> </property> <property key="simpleMethod.error_show_service_name"> <value xml:lang="en">calling service ${serviceName} in ${methodName}</value> <value xml:lang="it">eseguendo il servizio ${serviceName} in ${methodName}</value> <value xml:lang="ja">ãµã¼ãã¹ ${serviceName} ã ${methodName} ã§å¼ã³åºã</value> <value xml:lang="zh">å¨${methodName}ä¸è°ç¨æå¡${serviceName} </value> + <value xml:lang="zh_TW">å¨${methodName}ä¸å¼å«æå${serviceName} </value> </property> <property key="simpleMethod.must_logged_process"> <value xml:lang="de">Sie müssen am System angemeldet sein um [${shortDescription}] auszuführen</value> @@ -62,6 +63,6 @@ <value xml:lang="ru">ÐÐ»Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð¸Ñ Ð¿ÑоÑеÑÑа ${shortDescription} Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð·Ð°ÑегиÑÑÑиÑоваÑÑÑÑ Ð² ÑиÑÑеме</value> <value xml:lang="th">à¸à¸¸à¸à¸à¹à¸à¸à¸à¸³à¸à¸²à¸£à¹à¸à¹à¸²à¸ªà¸¹à¹à¸£à¸°à¸à¸à¹à¸à¸à¸²à¸£à¸à¸£à¸°à¸¡à¸§à¸¥à¸à¸¥ [${shortDescription}] à¹à¸«à¹à¹à¸ªà¸£à¹à¸à¸ªà¸¡à¸à¸¹à¸£à¸à¹</value> <value xml:lang="zh">ä½ å¿ é¡»ç»å½æè½å®æ${shortDescription}æ¥éª¤</value> - <value xml:lang="zh_TW">ä½ å¿ é ç»éæè½å®æ${shortDescription}æ¥é©</value> + <value xml:lang="zh_TW">ä½ å¿ é ç»å ¥æè½å®æ${shortDescription}æ¥é©</value> </property> </resource> Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java?rev=1621696&r1=1621695&r2=1621696&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java Mon Sep 1 07:29:23 2014 @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -84,7 +85,7 @@ public final class SimpleMethod extends private static final String[] DEPRECATED_ATTRIBUTES = {"parameter-map-name", "locale-name", "delegator-name", "security-name", "dispatcher-name", "user-login-name"}; private static final Map<String, MethodOperation.Factory<MethodOperation>> methodOperationFactories; private static final UtilCache<String, Map<String, SimpleMethod>> simpleMethodsDirectCache = UtilCache.createUtilCache("minilang.SimpleMethodsDirect", 0, 0); - private static final UtilCache<String, Map<String, SimpleMethod>> simpleMethodsResourceCache = UtilCache.createUtilCache("minilang.SimpleMethodsResource", 0, 0); + private static final UtilCache<String, SimpleMethod> simpleMethodsResourceCache = UtilCache.createUtilCache("minilang.SimpleMethodsResource", 0, 0); static { Map<String, MethodOperation.Factory<MethodOperation>> mapFactories = new HashMap<String, MethodOperation.Factory<MethodOperation>>(); @@ -134,7 +135,7 @@ public final class SimpleMethod extends } private static Map<String, SimpleMethod> getAllSimpleMethods(URL xmlURL) throws MiniLangException { - Map<String, SimpleMethod> simpleMethods = new HashMap<String, SimpleMethod>(); + Map<String, SimpleMethod> simpleMethods = new LinkedHashMap<String, SimpleMethod>(); Document document = null; try { document = UtilXml.readXmlDocument(xmlURL, true, true); @@ -160,14 +161,31 @@ public final class SimpleMethod extends public static SimpleMethod getSimpleMethod(String xmlResource, String methodName, ClassLoader loader) throws MiniLangException { Assert.notNull("methodName", methodName); - Map<String, SimpleMethod> simpleMethods = getSimpleMethods(xmlResource, loader); - return simpleMethods.get(methodName); + String key = xmlResource.concat("#").concat(methodName); + SimpleMethod method = simpleMethodsResourceCache.get(key); + if (method == null) { + Map<String, SimpleMethod> simpleMethods = getSimpleMethods(xmlResource, loader); + for (Map.Entry<String, SimpleMethod> entry : simpleMethods.entrySet()) { + String putKey = xmlResource.concat("#").concat(entry.getKey()); + simpleMethodsResourceCache.putIfAbsent(putKey, entry.getValue()); + } + } + return simpleMethodsResourceCache.get(key); } public static SimpleMethod getSimpleMethod(URL xmlUrl, String methodName) throws MiniLangException { Assert.notNull("methodName", methodName); - Map<String, SimpleMethod> simpleMethods = getSimpleMethods(xmlUrl); - return simpleMethods.get(methodName); + String xmlResource = xmlUrl.toString(); + String key = xmlResource.concat("#").concat(methodName); + SimpleMethod method = simpleMethodsResourceCache.get(key); + if (method == null) { + Map<String, SimpleMethod> simpleMethods = getAllSimpleMethods(xmlUrl); + for (Map.Entry<String, SimpleMethod> entry : simpleMethods.entrySet()) { + String putKey = xmlResource.concat("#").concat(entry.getKey()); + simpleMethodsResourceCache.putIfAbsent(putKey, entry.getValue()); + } + } + return simpleMethodsResourceCache.get(key); } private static Map<String, SimpleMethod> getSimpleMethods(String xmlResource, ClassLoader loader) throws MiniLangException { @@ -181,43 +199,23 @@ public final class SimpleMethod extends if (xmlURL == null) { throw new MiniLangException("Could not find SimpleMethod XML document in resource: " + xmlResource); } - return getSimpleMethods(xmlURL); - } - - private static Map<String, SimpleMethod> getSimpleMethods(URL xmlURL) throws MiniLangException { - Assert.notNull("xmlURL", xmlURL); - String cacheKey = xmlURL.toString(); - Map<String, SimpleMethod> simpleMethods = simpleMethodsResourceCache.get(cacheKey); - if (simpleMethods == null) { - simpleMethods = getAllSimpleMethods(xmlURL); - simpleMethods = simpleMethodsResourceCache.putIfAbsentAndGet(cacheKey, simpleMethods); - } - return simpleMethods; + return getAllSimpleMethods(xmlURL); } + /** + * Returns a List of <code>SimpleMethod</code> objects compiled from <code>xmlResource</code>. + * The ordering in the List is the same as the XML file. + * <p>This method is used by unit test framework to run tests in the order they appear in the XML file. + * Method caching is bypassed since the methods are executed only once.</p> + * + * @param xmlResource + * @param loader + * @return + * @throws MiniLangException + */ public static List<SimpleMethod> getSimpleMethodsList(String xmlResource, ClassLoader loader) throws MiniLangException { - Assert.notNull("xmlResource", xmlResource); - List<SimpleMethod> simpleMethods = new ArrayList<SimpleMethod>(); - // Let the standard Map returning method take care of caching and compilation Map<String, SimpleMethod> simpleMethodMap = getSimpleMethods(xmlResource, loader); - // Load and traverse the document again to get a correctly ordered list of methods - URL xmlURL = null; - try { - xmlURL = FlexibleLocation.resolveLocation(xmlResource, loader); - } catch (MalformedURLException e) { - throw new MiniLangException("Could not find SimpleMethod XML document in resource: " + xmlResource + ": ", e); - } - Document document = null; - try { - document = UtilXml.readXmlDocument(xmlURL, MiniLangValidate.validationOn(), true); - } catch (Exception e) { - throw new MiniLangException("Could not read SimpleMethod XML document [" + xmlURL + "]: ", e); - } - Element rootElement = document.getDocumentElement(); - for (Element simpleMethodElement : UtilXml.childElementList(rootElement, "simple-method")) { - simpleMethods.add(simpleMethodMap.get(simpleMethodElement.getAttribute("method-name"))); - } - return simpleMethods; + return new ArrayList<SimpleMethod>(simpleMethodMap.values()); } public static List<MethodOperation> readOperations(Element simpleMethodElement, SimpleMethod simpleMethod) throws MiniLangException { Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java?rev=1621696&r1=1621695&r2=1621696&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java Mon Sep 1 07:29:23 2014 @@ -169,10 +169,6 @@ public final class CallSimpleMethod exte return this.methodName; } - public SimpleMethod getSimpleMethodToCall(ClassLoader loader) throws MiniLangException { - return SimpleMethod.getSimpleMethod(xmlResource, methodName, loader); - } - public String getXmlResource() { return this.xmlResource; } Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/resources/templates/UiLabels.xml URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/resources/templates/UiLabels.xml?rev=1621696&r1=1621695&r2=1621696&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/resources/templates/UiLabels.xml (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/resources/templates/UiLabels.xml Mon Sep 1 07:29:23 2014 @@ -3,17 +3,21 @@ <property key="@component-resource-name@Application"> <value xml:lang="en">@component-resource-name@ Application</value> <value xml:lang="zh">@component-resource-name@åºç¨ç¨åº</value> + <value xml:lang="zh_TW">@component-resource-name@æç¨ç¨åº</value> </property> <property key="@component-resource-name@CompanyName"> <value xml:lang="en">OFBiz: @component-resource-name@</value> + <value xml:lang="zh_TW">OFBiz: @component-resource-name@</value> </property> <property key="@component-resource-name@CompanySubtitle"> <value xml:lang="en">Part of the Open For Business Family of Open Source Software</value> <value xml:lang="it">Un modulo della famiglia di software open source Open For Business</value> <value xml:lang="zh">弿ºè½¯ä»¶OFBizçç»æé¨å</value> + <value xml:lang="zh_TW">éæºè»é«OFBizçç»æé¨å</value> </property> <property key="@component-resource-name@ViewPermissionError"> <value xml:lang="en">You are not allowed to view this page.</value> <value xml:lang="zh">ä¸å è®¸ä½ æµè§è¿ä¸ªé¡µé¢ã</value> + <value xml:lang="zh_TW">ä¸å 許æ¨ç覽éåé é¢ã</value> </property> </resource> \ No newline at end of file |
Free forum by Nabble | Edit this page |