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

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


0001:        /*******************************************************************************
0002:         * Licensed to the Apache Software Foundation (ASF) under one
0003:         * or more contributor license agreements.  See the NOTICE file
0004:         * distributed with this work for additional information
0005:         * regarding copyright ownership.  The ASF licenses this file
0006:         * to you under the Apache License, Version 2.0 (the
0007:         * "License"); you may not use this file except in compliance
0008:         * with the License.  You may obtain a copy of the License at
0009:         * 
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         * 
0012:         * Unless required by applicable law or agreed to in writing,
0013:         * software distributed under the License is distributed on an
0014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015:         * KIND, either express or implied.  See the License for the
0016:         * specific language governing permissions and limitations
0017:         * under the License.
0018:         *******************************************************************************/package org.ofbiz.entityext.synchronization;
0019:
0020:        import java.io.IOException;
0021:        import java.sql.Timestamp;
0022:        import java.util.ArrayList;
0023:        import java.util.HashMap;
0024:        import java.util.HashSet;
0025:        import java.util.Iterator;
0026:        import java.util.LinkedList;
0027:        import java.util.List;
0028:        import java.util.Map;
0029:        import java.util.Set;
0030:        import javax.xml.parsers.ParserConfigurationException;
0031:
0032:        import org.ofbiz.base.util.Debug;
0033:        import org.ofbiz.base.util.UtilDateTime;
0034:        import org.ofbiz.base.util.UtilMisc;
0035:        import org.ofbiz.base.util.UtilValidate;
0036:        import org.ofbiz.entity.GenericDelegator;
0037:        import org.ofbiz.entity.GenericEntity;
0038:        import org.ofbiz.entity.GenericEntityException;
0039:        import org.ofbiz.entity.GenericValue;
0040:        import org.ofbiz.entity.condition.EntityCondition;
0041:        import org.ofbiz.entity.condition.EntityConditionList;
0042:        import org.ofbiz.entity.condition.EntityExpr;
0043:        import org.ofbiz.entity.condition.EntityOperator;
0044:        import org.ofbiz.entity.model.ModelEntity;
0045:        import org.ofbiz.entity.model.ModelViewEntity;
0046:        import org.ofbiz.entity.serialize.SerializeException;
0047:        import org.ofbiz.entity.serialize.XmlSerializer;
0048:        import org.ofbiz.entity.transaction.GenericTransactionException;
0049:        import org.ofbiz.entity.transaction.TransactionUtil;
0050:        import org.ofbiz.entity.util.EntityListIterator;
0051:        import org.ofbiz.service.DispatchContext;
0052:        import org.ofbiz.service.GeneralServiceException;
0053:        import org.ofbiz.service.GenericServiceException;
0054:        import org.ofbiz.service.LocalDispatcher;
0055:        import org.ofbiz.service.ModelService;
0056:        import org.ofbiz.service.ServiceUtil;
0057:
0058:        import org.xml.sax.SAXException;
0059:
0060:        /**
0061:         * Entity Engine Sync Services
0062:         */
0063:        public class EntitySyncContext {
0064:
0065:            public static final String module = EntitySyncContext.class
0066:                    .getName();
0067:
0068:            // set default split to 10 seconds, ie try not to get too much data moving over at once
0069:            public static final long defaultSyncSplitMillis = 10000;
0070:
0071:            // default offline split is 30 minutes
0072:            public static final long defaultOfflineSyncSplitMillis = 1800000;
0073:
0074:            // default to 5 minutes
0075:            public static final long defaultSyncEndBufferMillis = 300000;
0076:
0077:            // default to 2 hours, 120m, 7200s
0078:            public static final long defaultMaxRunningNoUpdateMillis = 7200000;
0079:
0080:            public GenericDelegator delegator;
0081:            public LocalDispatcher dispatcher;
0082:            public Map context;
0083:
0084:            public GenericValue userLogin;
0085:            public boolean isOfflineSync = false;
0086:
0087:            public String entitySyncId;
0088:            public GenericValue entitySync;
0089:
0090:            public String targetServiceName;
0091:            public String targetDelegatorName;
0092:
0093:            public Timestamp syncEndStamp;
0094:            public long offlineSyncSplitMillis = defaultOfflineSyncSplitMillis;
0095:            public long syncSplitMillis = defaultSyncSplitMillis;
0096:            public long syncEndBufferMillis = defaultSyncEndBufferMillis;
0097:            public long maxRunningNoUpdateMillis = defaultMaxRunningNoUpdateMillis;
0098:
0099:            public Timestamp lastSuccessfulSynchTime;
0100:            public List entityModelToUseList;
0101:            public Set entityNameToUseSet;
0102:            public Timestamp currentRunStartTime;
0103:            public Timestamp currentRunEndTime;
0104:
0105:            // these values are used to make this more efficient; if we run into an entity that has 0 
0106:            //results for a given time block, we will do a query to find the next create/update/remove
0107:            //time for that entity, and also keep track of a global next with the lowest future next value;
0108:            //using these we can skip a lot of queries and speed this up significantly
0109:            public Map nextEntityCreateTxTime = new HashMap();
0110:            public Map nextEntityUpdateTxTime = new HashMap();
0111:            public Timestamp nextCreateTxTime = null;
0112:            public Timestamp nextUpdateTxTime = null;
0113:            public Timestamp nextRemoveTxTime = null;
0114:
0115:            // this is the other part of the history PK, leave null until we create the history object
0116:            public Timestamp startDate = null;
0117:
0118:            long toCreateInserted = 0;
0119:            long toCreateUpdated = 0;
0120:            long toCreateNotUpdated = 0;
0121:            long toStoreInserted = 0;
0122:            long toStoreUpdated = 0;
0123:            long toStoreNotUpdated = 0;
0124:            long toRemoveDeleted = 0;
0125:            long toRemoveAlreadyDeleted = 0;
0126:
0127:            long totalRowsExported = 0;
0128:            long totalRowsToCreate = 0;
0129:            long totalRowsToStore = 0;
0130:            long totalRowsToRemove = 0;
0131:
0132:            long totalRowsPerSplit = 0;
0133:            long totalStoreCalls = 0;
0134:            long totalSplits = 0;
0135:            long perSplitMinMillis = Long.MAX_VALUE;
0136:            long perSplitMaxMillis = 0;
0137:            long perSplitMinItems = Long.MAX_VALUE;
0138:            long perSplitMaxItems = 0;
0139:            long splitStartTime = 0;
0140:
0141:            public EntitySyncContext(DispatchContext dctx, Map context)
0142:                    throws SyncDataErrorException, SyncAbortException {
0143:                this .context = context;
0144:                this .dispatcher = dctx.getDispatcher();
0145:
0146:                this .delegator = dctx.getDelegator();
0147:                // what to do with the delegatorName? this is the delegatorName to use in this service...
0148:                String delegatorName = (String) context.get("delegatorName");
0149:                if (UtilValidate.isNotEmpty(delegatorName)) {
0150:                    this .delegator = GenericDelegator
0151:                            .getGenericDelegator(delegatorName);
0152:                }
0153:
0154:                this .userLogin = (GenericValue) context.get("userLogin");
0155:
0156:                this .entitySyncId = (String) context.get("entitySyncId");
0157:                Debug.logInfo("Creating EntitySyncContext with entitySyncId="
0158:                        + entitySyncId, module);
0159:
0160:                boolean beganTransaction = false;
0161:                try {
0162:                    beganTransaction = TransactionUtil.begin(7200);
0163:                } catch (GenericTransactionException e) {
0164:                    throw new SyncDataErrorException(
0165:                            "Unable to begin JTA transaction", e);
0166:                }
0167:
0168:                try {
0169:                    this .entitySync = delegator.findByPrimaryKey("EntitySync",
0170:                            UtilMisc.toMap("entitySyncId", this .entitySyncId));
0171:                    if (this .entitySync == null) {
0172:                        throw new SyncAbortException("Not running EntitySync ["
0173:                                + entitySyncId
0174:                                + "], no record found with that ID.");
0175:                    }
0176:
0177:                    targetServiceName = entitySync
0178:                            .getString("targetServiceName");
0179:                    targetDelegatorName = entitySync
0180:                            .getString("targetDelegatorName");
0181:
0182:                    // make the last time to sync X minutes before the current time so that if this machines clock is up to that amount of time 
0183:                    //ahead of another machine writing to the DB it will still work fine and not lose any data
0184:                    syncEndStamp = new Timestamp(System.currentTimeMillis()
0185:                            - syncEndBufferMillis);
0186:
0187:                    this .offlineSyncSplitMillis = getOfflineSyncSplitMillis(entitySync);
0188:                    this .syncSplitMillis = getSyncSplitMillis(entitySync);
0189:                    this .syncEndBufferMillis = getSyncEndBufferMillis(entitySync);
0190:                    this .maxRunningNoUpdateMillis = getMaxRunningNoUpdateMillis(entitySync);
0191:
0192:                    this .lastSuccessfulSynchTime = entitySync
0193:                            .getTimestamp("lastSuccessfulSynchTime");
0194:                    this .entityModelToUseList = this .makeEntityModelToUseList();
0195:                    this .entityNameToUseSet = this .makeEntityNameToUseSet();
0196:
0197:                    // set start and end times for the first/current pass
0198:                    this .currentRunStartTime = getCurrentRunStartTime(
0199:                            lastSuccessfulSynchTime, entityModelToUseList,
0200:                            delegator);
0201:                    this .setCurrentRunEndTime();
0202:
0203:                    // this is mostly for the pull side... will always be null for at the beginning of a push process, to be filled in later
0204:                    this .startDate = (Timestamp) context.get("startDate");
0205:                } catch (GenericEntityException e) {
0206:                    try {
0207:                        TransactionUtil
0208:                                .rollback(
0209:                                        beganTransaction,
0210:                                        "Entity Engine error while getting Entity Sync init information",
0211:                                        e);
0212:                    } catch (GenericTransactionException e2) {
0213:                        Debug.logWarning(e2, "Unable to call rollback()",
0214:                                module);
0215:                    }
0216:                    throw new SyncDataErrorException(
0217:                            "Error initializing EntitySync Context", e);
0218:                }
0219:
0220:                try {
0221:                    TransactionUtil.commit(beganTransaction);
0222:                } catch (GenericTransactionException e) {
0223:                    throw new SyncDataErrorException(
0224:                            "Unable to commit transaction", e);
0225:                }
0226:            }
0227:
0228:            /**
0229:             * To see if it is running check: 
0230:             *  - in the running status 
0231:             *  - AND when the entitySync was last updated, and if it was more than maxRunningNoUpdateMillis ago, then don't consider it to be running
0232:             * @return boolean representing if the EntitySync should be considered running
0233:             */
0234:            public boolean isEntitySyncRunning() {
0235:                boolean isInRunning = ("ESR_RUNNING".equals(this .entitySync
0236:                        .getString("runStatusId")) || "ESR_PENDING"
0237:                        .equals(this .entitySync.getString("runStatusId")));
0238:
0239:                if (!isInRunning) {
0240:                    return false;
0241:                }
0242:
0243:                Timestamp esLastUpdated = this .entitySync
0244:                        .getTimestamp(ModelEntity.STAMP_FIELD);
0245:                if (esLastUpdated == null) {
0246:                    // shouldn't ever happen, but just in case; assume is running if we don't know when it was last updated
0247:                    return true;
0248:                }
0249:                long esLastUpdatedMillis = esLastUpdated.getTime();
0250:                long nowTimestampMillis = UtilDateTime.nowTimestamp().getTime();
0251:                long timeSinceUpdated = nowTimestampMillis
0252:                        - esLastUpdatedMillis;
0253:                if (timeSinceUpdated > this .maxRunningNoUpdateMillis) {
0254:                    // it has been longer than the maxRunningNoUpdateMillis, so don't consider it running
0255:                    return false;
0256:                }
0257:
0258:                return true;
0259:            }
0260:
0261:            public boolean hasMoreTimeToSync() {
0262:                return currentRunStartTime.before(syncEndStamp);
0263:            }
0264:
0265:            protected void setCurrentRunEndTime() {
0266:                this .currentRunEndTime = getNextRunEndTime();
0267:            }
0268:
0269:            protected Timestamp getNextRunEndTime() {
0270:                long syncSplit = this .isOfflineSync ? offlineSyncSplitMillis
0271:                        : syncSplitMillis;
0272:                Timestamp nextRunEndTime = new Timestamp(
0273:                        this .currentRunStartTime.getTime() + syncSplit);
0274:                if (nextRunEndTime.after(this .syncEndStamp)) {
0275:                    nextRunEndTime = this .syncEndStamp;
0276:                }
0277:                return nextRunEndTime;
0278:            }
0279:
0280:            public void advanceRunTimes() {
0281:                this .currentRunStartTime = this .currentRunEndTime;
0282:                this .setCurrentRunEndTime();
0283:            }
0284:
0285:            public void setSplitStartTime() {
0286:                this .splitStartTime = System.currentTimeMillis();
0287:            }
0288:
0289:            protected static long getSyncSplitMillis(GenericValue entitySync) {
0290:                long splitMillis = defaultSyncSplitMillis;
0291:                Long syncSplitMillis = entitySync.getLong("syncSplitMillis");
0292:                if (syncSplitMillis != null) {
0293:                    splitMillis = syncSplitMillis.longValue();
0294:                }
0295:                return splitMillis;
0296:            }
0297:
0298:            protected static long getOfflineSyncSplitMillis(
0299:                    GenericValue entitySync) {
0300:                long splitMillis = defaultOfflineSyncSplitMillis;
0301:                Long syncSplitMillis = entitySync
0302:                        .getLong("offlineSyncSplitMillis");
0303:                if (syncSplitMillis != null) {
0304:                    splitMillis = syncSplitMillis.longValue();
0305:                }
0306:                return splitMillis;
0307:            }
0308:
0309:            protected static long getSyncEndBufferMillis(GenericValue entitySync) {
0310:                long syncEndBufferMillis = defaultSyncEndBufferMillis;
0311:                Long syncEndBufferMillisLong = entitySync
0312:                        .getLong("syncEndBufferMillis");
0313:                if (syncEndBufferMillisLong != null) {
0314:                    syncEndBufferMillis = syncEndBufferMillisLong.longValue();
0315:                }
0316:                return syncEndBufferMillis;
0317:            }
0318:
0319:            protected static long getMaxRunningNoUpdateMillis(
0320:                    GenericValue entitySync) {
0321:                long maxRunningNoUpdateMillis = defaultMaxRunningNoUpdateMillis;
0322:                Long maxRunningNoUpdateMillisLong = entitySync
0323:                        .getLong("maxRunningNoUpdateMillis");
0324:                if (maxRunningNoUpdateMillisLong != null) {
0325:                    maxRunningNoUpdateMillis = maxRunningNoUpdateMillisLong
0326:                            .longValue();
0327:                }
0328:                return maxRunningNoUpdateMillis;
0329:            }
0330:
0331:            /** create history record, target service should run in own tx */
0332:            public void createInitialHistory() throws SyncDataErrorException,
0333:                    SyncServiceErrorException {
0334:                String errorMsg = "Not running EntitySync [" + entitySyncId
0335:                        + "], could not create EntitySyncHistory";
0336:                try {
0337:                    Map initialHistoryRes = dispatcher.runSync(
0338:                            "createEntitySyncHistory", UtilMisc.toMap(
0339:                                    "entitySyncId", entitySyncId,
0340:                                    "runStatusId", "ESR_RUNNING",
0341:                                    "beginningSynchTime",
0342:                                    this .currentRunStartTime,
0343:                                    "lastCandidateEndTime",
0344:                                    this .currentRunEndTime, "userLogin",
0345:                                    userLogin));
0346:                    if (ServiceUtil.isError(initialHistoryRes)) {
0347:                        throw new SyncDataErrorException(errorMsg, null, null,
0348:                                initialHistoryRes, null);
0349:                    }
0350:                    this .startDate = (Timestamp) initialHistoryRes
0351:                            .get("startDate");
0352:                } catch (GenericServiceException e) {
0353:                    throw new SyncServiceErrorException(errorMsg, e);
0354:                }
0355:            }
0356:
0357:            public ArrayList assembleValuesToCreate()
0358:                    throws SyncDataErrorException {
0359:                // first grab all values inserted in the date range, then get the updates (leaving out all values inserted in the data range)
0360:                ArrayList valuesToCreate = new ArrayList(); // make it an ArrayList to easily merge in sorted lists
0361:
0362:                if (this .nextCreateTxTime != null
0363:                        && (this .nextCreateTxTime.equals(currentRunEndTime) || this .nextCreateTxTime
0364:                                .after(currentRunEndTime))) {
0365:                    // this means that for all entities in this pack we found on the last pass that there would be nothing for this one, so just return nothing...
0366:                    return valuesToCreate;
0367:                }
0368:
0369:                //Debug.logInfo("Getting values to create; currentRunStartTime=" + currentRunStartTime + ", currentRunEndTime=" + currentRunEndTime, module);
0370:
0371:                int entitiesSkippedForKnownNext = 0;
0372:
0373:                // iterate through entities, get all records with tx stamp in the current time range, put all in a single list
0374:                Iterator entityModelToUseCreateIter = entityModelToUseList
0375:                        .iterator();
0376:                while (entityModelToUseCreateIter.hasNext()) {
0377:                    int insertBefore = 0;
0378:                    ModelEntity modelEntity = (ModelEntity) entityModelToUseCreateIter
0379:                            .next();
0380:
0381:                    // first test to see if we know that there are no records for this entity in this time period...
0382:                    Timestamp knownNextCreateTime = (Timestamp) this .nextEntityCreateTxTime
0383:                            .get(modelEntity.getEntityName());
0384:                    if (knownNextCreateTime != null
0385:                            && (knownNextCreateTime.equals(currentRunEndTime) || knownNextCreateTime
0386:                                    .after(currentRunEndTime))) {
0387:                        //Debug.logInfo("In assembleValuesToCreate found knownNextCreateTime [" + knownNextCreateTime + "] after currentRunEndTime [" + currentRunEndTime + "], so skipping time per period for entity [" + modelEntity.getEntityName() + "]", module);
0388:                        entitiesSkippedForKnownNext++;
0389:                        continue;
0390:                    }
0391:
0392:                    boolean beganTransaction = false;
0393:                    try {
0394:                        beganTransaction = TransactionUtil.begin(7200);
0395:                    } catch (GenericTransactionException e) {
0396:                        throw new SyncDataErrorException(
0397:                                "Unable to begin JTA transaction", e);
0398:                    }
0399:
0400:                    try {
0401:                        // get the values created within the current time range
0402:                        EntityCondition findValCondition = new EntityConditionList(
0403:                                UtilMisc.toList(new EntityExpr(
0404:                                        ModelEntity.CREATE_STAMP_TX_FIELD,
0405:                                        EntityOperator.GREATER_THAN_EQUAL_TO,
0406:                                        currentRunStartTime), new EntityExpr(
0407:                                        ModelEntity.CREATE_STAMP_TX_FIELD,
0408:                                        EntityOperator.LESS_THAN,
0409:                                        currentRunEndTime)), EntityOperator.AND);
0410:                        EntityListIterator eli = delegator
0411:                                .findListIteratorByCondition(
0412:                                        modelEntity.getEntityName(),
0413:                                        findValCondition,
0414:                                        null,
0415:                                        UtilMisc
0416:                                                .toList(
0417:                                                        ModelEntity.CREATE_STAMP_TX_FIELD,
0418:                                                        ModelEntity.CREATE_STAMP_FIELD));
0419:                        GenericValue nextValue = null;
0420:                        long valuesPerEntity = 0;
0421:                        while ((nextValue = (GenericValue) eli.next()) != null) {
0422:                            // sort by the tx stamp and then the record stamp 
0423:                            // find first value in valuesToStore list, starting with the current insertBefore value, that has a CREATE_STAMP_TX_FIELD after the nextValue.CREATE_STAMP_TX_FIELD, then do the same with CREATE_STAMP_FIELD
0424:                            while (insertBefore < valuesToCreate.size()
0425:                                    && ((GenericValue) valuesToCreate
0426:                                            .get(insertBefore))
0427:                                            .getTimestamp(
0428:                                                    ModelEntity.CREATE_STAMP_TX_FIELD)
0429:                                            .before(
0430:                                                    nextValue
0431:                                                            .getTimestamp(ModelEntity.CREATE_STAMP_TX_FIELD))) {
0432:                                insertBefore++;
0433:                            }
0434:                            while (insertBefore < valuesToCreate.size()
0435:                                    && ((GenericValue) valuesToCreate
0436:                                            .get(insertBefore))
0437:                                            .getTimestamp(
0438:                                                    ModelEntity.CREATE_STAMP_FIELD)
0439:                                            .before(
0440:                                                    nextValue
0441:                                                            .getTimestamp(ModelEntity.CREATE_STAMP_FIELD))) {
0442:                                insertBefore++;
0443:                            }
0444:                            valuesToCreate.add(insertBefore, nextValue);
0445:                            valuesPerEntity++;
0446:                        }
0447:                        eli.close();
0448:
0449:                        // definately remove this message and related data gathering
0450:                        //long preCount = delegator.findCountByCondition(modelEntity.getEntityName(), findValCondition, null);
0451:                        //long entityTotalCount = delegator.findCountByCondition(modelEntity.getEntityName(), null, null);
0452:                        //if (entityTotalCount > 0 || preCount > 0 || valuesPerEntity > 0) Debug.logInfo("Got " + valuesPerEntity + "/" + preCount + "/" + entityTotalCount + " values for entity " + modelEntity.getEntityName(), module);
0453:
0454:                        // if we didn't find anything for this entity, find the next value's Timestamp and keep track of it
0455:                        if (valuesPerEntity == 0) {
0456:                            Timestamp startCheckStamp = new Timestamp(System
0457:                                    .currentTimeMillis()
0458:                                    - syncEndBufferMillis);
0459:
0460:                            EntityCondition findNextCondition = new EntityConditionList(
0461:                                    UtilMisc
0462:                                            .toList(
0463:                                                    new EntityExpr(
0464:                                                            ModelEntity.CREATE_STAMP_TX_FIELD,
0465:                                                            EntityOperator.NOT_EQUAL,
0466:                                                            null),
0467:                                                    new EntityExpr(
0468:                                                            ModelEntity.CREATE_STAMP_TX_FIELD,
0469:                                                            EntityOperator.GREATER_THAN_EQUAL_TO,
0470:                                                            currentRunEndTime)),
0471:                                    EntityOperator.AND);
0472:                            EntityListIterator eliNext = delegator
0473:                                    .findListIteratorByCondition(
0474:                                            modelEntity.getEntityName(),
0475:                                            findNextCondition,
0476:                                            null,
0477:                                            UtilMisc
0478:                                                    .toList(ModelEntity.CREATE_STAMP_TX_FIELD));
0479:                            // get the first element and it's tx time value...
0480:                            GenericValue firstVal = (GenericValue) eliNext
0481:                                    .next();
0482:                            eliNext.close();
0483:                            Timestamp nextTxTime;
0484:                            if (firstVal != null) {
0485:                                nextTxTime = firstVal
0486:                                        .getTimestamp(ModelEntity.CREATE_STAMP_TX_FIELD);
0487:                            } else {
0488:                                // no results? well, then it's safe to say that up to the pre-querytime (minus the buffer, as usual) we are okay
0489:                                nextTxTime = startCheckStamp;
0490:                            }
0491:                            if (this .nextCreateTxTime == null
0492:                                    || nextTxTime.before(this .nextCreateTxTime)) {
0493:                                this .nextCreateTxTime = nextTxTime;
0494:                                Debug.logInfo(
0495:                                        "EntitySync: Set nextCreateTxTime to ["
0496:                                                + nextTxTime + "]", module);
0497:                            }
0498:                            Timestamp curEntityNextTxTime = (Timestamp) this .nextEntityCreateTxTime
0499:                                    .get(modelEntity.getEntityName());
0500:                            if (curEntityNextTxTime == null
0501:                                    || nextTxTime.before(curEntityNextTxTime)) {
0502:                                this .nextEntityCreateTxTime.put(modelEntity
0503:                                        .getEntityName(), nextTxTime);
0504:                                Debug.logInfo(
0505:                                        "EntitySync: Set nextEntityCreateTxTime to ["
0506:                                                + nextTxTime
0507:                                                + "] for the entity ["
0508:                                                + modelEntity.getEntityName()
0509:                                                + "]", module);
0510:                            }
0511:                        }
0512:                    } catch (GenericEntityException e) {
0513:                        try {
0514:                            TransactionUtil
0515:                                    .rollback(
0516:                                            beganTransaction,
0517:                                            "Entity Engine error in assembleValuesToCreate",
0518:                                            e);
0519:
0520:                        } catch (GenericTransactionException e2) {
0521:                            Debug.logWarning(e2, "Unable to call rollback()",
0522:                                    module);
0523:                        }
0524:                        throw new SyncDataErrorException(
0525:                                "Error getting values to create from the datasource",
0526:                                e);
0527:                    } catch (Throwable t) {
0528:                        try {
0529:                            TransactionUtil
0530:                                    .rollback(
0531:                                            beganTransaction,
0532:                                            "Throwable error in assembleValuesToCreate",
0533:                                            t);
0534:                        } catch (GenericTransactionException e2) {
0535:                            Debug.logWarning(e2, "Unable to call rollback()",
0536:                                    module);
0537:                        }
0538:                        throw new SyncDataErrorException(
0539:                                "Caught runtime error while getting values to create",
0540:                                t);
0541:                    }
0542:
0543:                    try {
0544:                        TransactionUtil.commit(beganTransaction);
0545:                    } catch (GenericTransactionException e) {
0546:                        throw new SyncDataErrorException(
0547:                                "Commit transaction failed", e);
0548:                    }
0549:                }
0550:
0551:                if (entitiesSkippedForKnownNext > 0) {
0552:                    if (Debug.infoOn())
0553:                        Debug.logInfo("In assembleValuesToCreate skipped ["
0554:                                + entitiesSkippedForKnownNext + "/"
0555:                                + entityModelToUseList
0556:                                + "] entities for the time period ending at ["
0557:                                + currentRunEndTime
0558:                                + "] because of next known create times",
0559:                                module);
0560:                }
0561:
0562:                // TEST SECTION: leave false for normal use
0563:                boolean logValues = false;
0564:                if (logValues && valuesToCreate.size() > 0) {
0565:                    StringBuffer toCreateInfo = new StringBuffer();
0566:                    Iterator valuesToCreateIter = valuesToCreate.iterator();
0567:                    while (valuesToCreateIter.hasNext()) {
0568:                        GenericValue valueToCreate = (GenericValue) valuesToCreateIter
0569:                                .next();
0570:                        toCreateInfo.append("\n-->[");
0571:                        toCreateInfo.append(valueToCreate
0572:                                .get(ModelEntity.CREATE_STAMP_TX_FIELD));
0573:                        toCreateInfo.append(":");
0574:                        toCreateInfo.append(valueToCreate
0575:                                .get(ModelEntity.CREATE_STAMP_FIELD));
0576:                        toCreateInfo.append("] ");
0577:                        toCreateInfo.append(valueToCreate.getPrimaryKey());
0578:                    }
0579:                    Debug.logInfo(toCreateInfo.toString(), module);
0580:                }
0581:
0582:                return valuesToCreate;
0583:            }
0584:
0585:            public ArrayList assembleValuesToStore()
0586:                    throws SyncDataErrorException {
0587:                // simulate two ordered lists and merge them on-the-fly for faster combined sorting
0588:                ArrayList valuesToStore = new ArrayList(); // make it an ArrayList to easily merge in sorted lists
0589:
0590:                if (this .nextUpdateTxTime != null
0591:                        && (this .nextUpdateTxTime.equals(currentRunEndTime) || this .nextUpdateTxTime
0592:                                .after(currentRunEndTime))) {
0593:                    // this means that for all entities in this pack we found on the last pass that there would be nothing for this one, so just return nothing...
0594:                    return valuesToStore;
0595:                }
0596:
0597:                // Debug.logInfo("Getting values to store; currentRunStartTime=" + currentRunStartTime + ", currentRunEndTime=" + currentRunEndTime, module);
0598:
0599:                int entitiesSkippedForKnownNext = 0;
0600:
0601:                // iterate through entities, get all records with tx stamp in the current time range, put all in a single list
0602:                Iterator entityModelToUseUpdateIter = entityModelToUseList
0603:                        .iterator();
0604:                while (entityModelToUseUpdateIter.hasNext()) {
0605:                    int insertBefore = 0;
0606:                    ModelEntity modelEntity = (ModelEntity) entityModelToUseUpdateIter
0607:                            .next();
0608:
0609:                    // first test to see if we know that there are no records for this entity in this time period...
0610:                    Timestamp knownNextUpdateTime = (Timestamp) this .nextEntityUpdateTxTime
0611:                            .get(modelEntity.getEntityName());
0612:                    if (knownNextUpdateTime != null
0613:                            && (knownNextUpdateTime.equals(currentRunEndTime) || knownNextUpdateTime
0614:                                    .after(currentRunEndTime))) {
0615:                        entitiesSkippedForKnownNext++;
0616:                        continue;
0617:                    }
0618:
0619:                    boolean beganTransaction = false;
0620:                    try {
0621:                        beganTransaction = TransactionUtil.begin(7200);
0622:                    } catch (GenericTransactionException e) {
0623:                        throw new SyncDataErrorException(
0624:                                "Unable to begin JTA transaction", e);
0625:                    }
0626:
0627:                    try {
0628:                        // get all values that were updated, but NOT created in the current time range; if no info on created stamp, that's okay we'll include it here because it won't have been included in the valuesToCreate list
0629:                        EntityCondition createdBeforeStartCond = new EntityExpr(
0630:                                new EntityExpr(
0631:                                        ModelEntity.CREATE_STAMP_TX_FIELD,
0632:                                        EntityOperator.EQUALS, null),
0633:                                EntityOperator.OR, new EntityExpr(
0634:                                        ModelEntity.CREATE_STAMP_TX_FIELD,
0635:                                        EntityOperator.LESS_THAN,
0636:                                        currentRunStartTime));
0637:                        EntityCondition findValCondition = new EntityConditionList(
0638:                                UtilMisc.toList(new EntityExpr(
0639:                                        ModelEntity.STAMP_TX_FIELD,
0640:                                        EntityOperator.GREATER_THAN_EQUAL_TO,
0641:                                        currentRunStartTime), new EntityExpr(
0642:                                        ModelEntity.STAMP_TX_FIELD,
0643:                                        EntityOperator.LESS_THAN,
0644:                                        currentRunEndTime),
0645:                                        createdBeforeStartCond),
0646:                                EntityOperator.AND);
0647:                        EntityListIterator eli = delegator
0648:                                .findListIteratorByCondition(modelEntity
0649:                                        .getEntityName(), findValCondition,
0650:                                        null, UtilMisc.toList(
0651:                                                ModelEntity.STAMP_TX_FIELD,
0652:                                                ModelEntity.STAMP_FIELD));
0653:                        GenericValue nextValue = null;
0654:                        long valuesPerEntity = 0;
0655:                        while ((nextValue = (GenericValue) eli.next()) != null) {
0656:                            // sort by the tx stamp and then the record stamp 
0657:                            // find first value in valuesToStore list, starting with the current insertBefore value, that has a STAMP_TX_FIELD after the nextValue.STAMP_TX_FIELD, then do the same with STAMP_FIELD
0658:                            while (insertBefore < valuesToStore.size()
0659:                                    && ((GenericValue) valuesToStore
0660:                                            .get(insertBefore))
0661:                                            .getTimestamp(
0662:                                                    ModelEntity.STAMP_TX_FIELD)
0663:                                            .before(
0664:                                                    nextValue
0665:                                                            .getTimestamp(ModelEntity.STAMP_TX_FIELD))) {
0666:                                insertBefore++;
0667:                            }
0668:                            while (insertBefore < valuesToStore.size()
0669:                                    && ((GenericValue) valuesToStore
0670:                                            .get(insertBefore))
0671:                                            .getTimestamp(
0672:                                                    ModelEntity.STAMP_FIELD)
0673:                                            .before(
0674:                                                    nextValue
0675:                                                            .getTimestamp(ModelEntity.STAMP_FIELD))) {
0676:                                insertBefore++;
0677:                            }
0678:                            valuesToStore.add(insertBefore, nextValue);
0679:                            valuesPerEntity++;
0680:                        }
0681:                        eli.close();
0682:
0683:                        // definately remove this message and related data gathering
0684:                        //long preCount = delegator.findCountByCondition(modelEntity.getEntityName(), findValCondition, null);
0685:                        //long entityTotalCount = delegator.findCountByCondition(modelEntity.getEntityName(), null, null);
0686:                        //if (entityTotalCount > 0 || preCount > 0 || valuesPerEntity > 0) Debug.logInfo("Got " + valuesPerEntity + "/" + preCount + "/" + entityTotalCount + " values for entity " + modelEntity.getEntityName(), module);
0687:
0688:                        // if we didn't find anything for this entity, find the next value's Timestamp and keep track of it
0689:                        if (valuesPerEntity == 0) {
0690:                            Timestamp startCheckStamp = new Timestamp(System
0691:                                    .currentTimeMillis()
0692:                                    - syncEndBufferMillis);
0693:
0694:                            EntityCondition findNextCondition = new EntityConditionList(
0695:                                    UtilMisc
0696:                                            .toList(
0697:                                                    new EntityExpr(
0698:                                                            ModelEntity.STAMP_TX_FIELD,
0699:                                                            EntityOperator.NOT_EQUAL,
0700:                                                            null),
0701:                                                    new EntityExpr(
0702:                                                            ModelEntity.STAMP_TX_FIELD,
0703:                                                            EntityOperator.GREATER_THAN_EQUAL_TO,
0704:                                                            currentRunEndTime),
0705:                                                    new EntityExpr(
0706:                                                            ModelEntity.CREATE_STAMP_TX_FIELD,
0707:                                                            EntityOperator.NOT_EQUAL,
0708:                                                            null),
0709:                                                    new EntityExpr(
0710:                                                            ModelEntity.CREATE_STAMP_TX_FIELD,
0711:                                                            EntityOperator.LESS_THAN,
0712:                                                            currentRunEndTime)),
0713:                                    EntityOperator.AND);
0714:                            EntityListIterator eliNext = delegator
0715:                                    .findListIteratorByCondition(
0716:                                            modelEntity.getEntityName(),
0717:                                            findNextCondition,
0718:                                            null,
0719:                                            UtilMisc
0720:                                                    .toList(ModelEntity.STAMP_TX_FIELD));
0721:                            // get the first element and it's tx time value...
0722:                            GenericValue firstVal = (GenericValue) eliNext
0723:                                    .next();
0724:                            eliNext.close();
0725:                            Timestamp nextTxTime;
0726:                            if (firstVal != null) {
0727:                                nextTxTime = firstVal
0728:                                        .getTimestamp(ModelEntity.CREATE_STAMP_TX_FIELD);
0729:                            } else {
0730:                                // no results? well, then it's safe to say that up to the pre-querytime (minus the buffer, as usual) we are okay
0731:                                nextTxTime = startCheckStamp;
0732:                            }
0733:                            if (this .nextUpdateTxTime == null
0734:                                    || nextTxTime.before(this .nextUpdateTxTime)) {
0735:                                this .nextUpdateTxTime = nextTxTime;
0736:                                Debug.logInfo(
0737:                                        "EntitySync: Set nextUpdateTxTime to ["
0738:                                                + nextTxTime + "]", module);
0739:                            }
0740:                            Timestamp curEntityNextTxTime = (Timestamp) this .nextEntityUpdateTxTime
0741:                                    .get(modelEntity.getEntityName());
0742:                            if (curEntityNextTxTime == null
0743:                                    || nextTxTime.before(curEntityNextTxTime)) {
0744:                                this .nextEntityUpdateTxTime.put(modelEntity
0745:                                        .getEntityName(), nextTxTime);
0746:                                Debug.logInfo(
0747:                                        "EntitySync: Set nextEntityUpdateTxTime to ["
0748:                                                + nextTxTime
0749:                                                + "] for the entity ["
0750:                                                + modelEntity.getEntityName()
0751:                                                + "]", module);
0752:                            }
0753:                        }
0754:                    } catch (GenericEntityException e) {
0755:                        try {
0756:                            TransactionUtil
0757:                                    .rollback(
0758:                                            beganTransaction,
0759:                                            "Entity Engine error in assembleValuesToStore",
0760:                                            e);
0761:                        } catch (GenericTransactionException e2) {
0762:                            Debug.logWarning(e2, "Unable to call rollback()",
0763:                                    module);
0764:                        }
0765:                        throw new SyncDataErrorException(
0766:                                "Error getting values to store from the datasource",
0767:                                e);
0768:                    } catch (Throwable t) {
0769:                        try {
0770:                            TransactionUtil
0771:                                    .rollback(
0772:                                            beganTransaction,
0773:                                            "General error in assembleValuesToStore",
0774:                                            t);
0775:                        } catch (GenericTransactionException e2) {
0776:                            Debug.logWarning(e2, "Unable to call rollback()",
0777:                                    module);
0778:                        }
0779:                        throw new SyncDataErrorException(
0780:                                "Caught runtime error while getting values to store",
0781:                                t);
0782:                    }
0783:
0784:                    try {
0785:                        TransactionUtil.commit(beganTransaction);
0786:                    } catch (GenericTransactionException e) {
0787:                        throw new SyncDataErrorException(
0788:                                "Commit transaction failed", e);
0789:                    }
0790:                }
0791:
0792:                if (entitiesSkippedForKnownNext > 0) {
0793:                    if (Debug.infoOn())
0794:                        Debug.logInfo("In assembleValuesToStore skipped ["
0795:                                + entitiesSkippedForKnownNext + "/"
0796:                                + entityModelToUseList
0797:                                + "] entities for the time period ending at ["
0798:                                + currentRunEndTime
0799:                                + "] because of next known update times",
0800:                                module);
0801:                }
0802:
0803:                // TEST SECTION: leave false for normal use
0804:                boolean logValues = false;
0805:                if (logValues && valuesToStore.size() > 0) {
0806:                    StringBuffer toStoreInfo = new StringBuffer();
0807:                    Iterator valuesToStoreIter = valuesToStore.iterator();
0808:                    while (valuesToStoreIter.hasNext()) {
0809:                        GenericValue valueToStore = (GenericValue) valuesToStoreIter
0810:                                .next();
0811:                        toStoreInfo.append("\n-->[");
0812:                        toStoreInfo.append(valueToStore
0813:                                .get(ModelEntity.STAMP_TX_FIELD));
0814:                        toStoreInfo.append(":");
0815:                        toStoreInfo.append(valueToStore
0816:                                .get(ModelEntity.STAMP_FIELD));
0817:                        toStoreInfo.append("] ");
0818:                        toStoreInfo.append(valueToStore.getPrimaryKey());
0819:                    }
0820:                    Debug.logInfo(toStoreInfo.toString(), module);
0821:                }
0822:
0823:                return valuesToStore;
0824:            }
0825:
0826:            public LinkedList assembleKeysToRemove()
0827:                    throws SyncDataErrorException {
0828:                // get all removed items from the given time range, add to list for those
0829:                LinkedList keysToRemove = new LinkedList();
0830:
0831:                if (this .nextRemoveTxTime != null
0832:                        && (this .nextRemoveTxTime.equals(currentRunEndTime) || this .nextRemoveTxTime
0833:                                .after(currentRunEndTime))) {
0834:                    // this means that for all entities in this pack we found on the last pass that there would be nothing for this one, so just return nothing...
0835:                    return keysToRemove;
0836:                }
0837:
0838:                //Debug.logInfo("Getting keys to remove; currentRunStartTime=" + currentRunStartTime + ", currentRunEndTime=" + currentRunEndTime, module);
0839:
0840:                boolean beganTransaction = false;
0841:                try {
0842:                    beganTransaction = TransactionUtil.begin(7200);
0843:                } catch (GenericTransactionException e) {
0844:                    throw new SyncDataErrorException(
0845:                            "Unable to begin JTA transaction", e);
0846:                }
0847:
0848:                try {
0849:                    // find all instances of this entity with the STAMP_TX_FIELD != null, sort ascending to get lowest/oldest value first, then grab first and consider as candidate currentRunStartTime
0850:                    EntityCondition findValCondition = new EntityConditionList(
0851:                            UtilMisc.toList(new EntityExpr(
0852:                                    ModelEntity.STAMP_TX_FIELD,
0853:                                    EntityOperator.GREATER_THAN_EQUAL_TO,
0854:                                    currentRunStartTime),
0855:                                    new EntityExpr(ModelEntity.STAMP_TX_FIELD,
0856:                                            EntityOperator.LESS_THAN,
0857:                                            currentRunEndTime)),
0858:                            EntityOperator.AND);
0859:                    EntityListIterator removeEli = delegator
0860:                            .findListIteratorByCondition("EntitySyncRemove",
0861:                                    findValCondition, null, UtilMisc.toList(
0862:                                            ModelEntity.STAMP_TX_FIELD,
0863:                                            ModelEntity.STAMP_FIELD));
0864:                    GenericValue entitySyncRemove = null;
0865:                    while ((entitySyncRemove = (GenericValue) removeEli.next()) != null) {
0866:                        // pull the PK from the EntitySyncRemove in the primaryKeyRemoved field, de-XML-serialize it 
0867:                        String primaryKeyRemoved = entitySyncRemove
0868:                                .getString("primaryKeyRemoved");
0869:                        GenericEntity pkToRemove = null;
0870:                        try {
0871:                            pkToRemove = (GenericEntity) XmlSerializer
0872:                                    .deserialize(primaryKeyRemoved, delegator);
0873:                        } catch (IOException e) {
0874:                            String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId ["
0875:                                    + entitySyncId
0876:                                    + "] and entitySyncRemoveId ["
0877:                                    + entitySyncRemove
0878:                                            .getString("entitySyncRemoveId")
0879:                                    + "]: " + e.toString();
0880:                            Debug.logError(e, errorMsg, module);
0881:                            throw new SyncDataErrorException(errorMsg, e);
0882:                        } catch (SAXException e) {
0883:                            String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId ["
0884:                                    + entitySyncId
0885:                                    + "] and entitySyncRemoveId ["
0886:                                    + entitySyncRemove
0887:                                            .getString("entitySyncRemoveId")
0888:                                    + "]: " + e.toString();
0889:                            Debug.logError(e, errorMsg, module);
0890:                            throw new SyncDataErrorException(errorMsg, e);
0891:                        } catch (ParserConfigurationException e) {
0892:                            String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId ["
0893:                                    + entitySyncId
0894:                                    + "] and entitySyncRemoveId ["
0895:                                    + entitySyncRemove
0896:                                            .getString("entitySyncRemoveId")
0897:                                    + "]: " + e.toString();
0898:                            Debug.logError(e, errorMsg, module);
0899:                            throw new SyncDataErrorException(errorMsg, e);
0900:                        } catch (SerializeException e) {
0901:                            String errorMsg = "Error deserializing GenericPK to remove in Entity Sync Data for entitySyncId ["
0902:                                    + entitySyncId
0903:                                    + "] and entitySyncRemoveId ["
0904:                                    + entitySyncRemove
0905:                                            .getString("entitySyncRemoveId")
0906:                                    + "]: " + e.toString();
0907:                            Debug.logError(e, errorMsg, module);
0908:                            throw new SyncDataErrorException(errorMsg, e);
0909:                        }
0910:
0911:                        // set the stamp fields for future reference
0912:                        pkToRemove.set(ModelEntity.STAMP_TX_FIELD,
0913:                                entitySyncRemove
0914:                                        .get(ModelEntity.STAMP_TX_FIELD));
0915:                        pkToRemove.set(ModelEntity.STAMP_FIELD,
0916:                                entitySyncRemove.get(ModelEntity.STAMP_FIELD));
0917:                        pkToRemove
0918:                                .set(
0919:                                        ModelEntity.CREATE_STAMP_TX_FIELD,
0920:                                        entitySyncRemove
0921:                                                .get(ModelEntity.CREATE_STAMP_TX_FIELD));
0922:                        pkToRemove.set(ModelEntity.CREATE_STAMP_FIELD,
0923:                                entitySyncRemove
0924:                                        .get(ModelEntity.CREATE_STAMP_FIELD));
0925:
0926:                        if (this .entityNameToUseSet.contains(pkToRemove
0927:                                .getEntityName())) {
0928:                            keysToRemove.add(pkToRemove);
0929:                        }
0930:                    }
0931:                    removeEli.close();
0932:
0933:                    // if we didn't find anything for this entity, find the next value's Timestamp and keep track of it
0934:                    if (keysToRemove.size() == 0) {
0935:                        EntityCondition findNextCondition = new EntityExpr(
0936:                                ModelEntity.STAMP_TX_FIELD,
0937:                                EntityOperator.GREATER_THAN_EQUAL_TO,
0938:                                currentRunEndTime);
0939:                        EntityListIterator eliNext = delegator
0940:                                .findListIteratorByCondition(
0941:                                        "EntitySyncRemove",
0942:                                        findNextCondition,
0943:                                        null,
0944:                                        UtilMisc
0945:                                                .toList(ModelEntity.STAMP_TX_FIELD));
0946:                        // get the first element and it's tx time value...
0947:                        GenericValue firstVal = (GenericValue) eliNext.next();
0948:                        eliNext.close();
0949:                        if (firstVal != null) {
0950:                            Timestamp nextTxTime = firstVal
0951:                                    .getTimestamp(ModelEntity.STAMP_TX_FIELD);
0952:                            if (this .nextUpdateTxTime == null
0953:                                    || nextTxTime.before(this .nextUpdateTxTime)) {
0954:                                this .nextUpdateTxTime = nextTxTime;
0955:                            }
0956:                        }
0957:                    }
0958:                } catch (GenericEntityException e) {
0959:                    try {
0960:                        TransactionUtil.rollback(beganTransaction,
0961:                                "Entity Engine error in assembleKeysToRemove",
0962:                                e);
0963:                    } catch (GenericTransactionException e2) {
0964:                        Debug.logWarning(e2, "Unable to call rollback()",
0965:                                module);
0966:                    }
0967:                    throw new SyncDataErrorException(
0968:                            "Error getting keys to remove from the datasource",
0969:                            e);
0970:                } catch (Throwable t) {
0971:                    try {
0972:                        TransactionUtil.rollback(beganTransaction,
0973:                                "General error in assembleKeysToRemove", t);
0974:                    } catch (GenericTransactionException e2) {
0975:                        Debug.logWarning(e2, "Unable to call rollback()",
0976:                                module);
0977:                    }
0978:                    throw new SyncDataErrorException(
0979:                            "Caught runtime error while getting keys to remove",
0980:                            t);
0981:                }
0982:
0983:                try {
0984:                    TransactionUtil.commit(beganTransaction);
0985:                } catch (GenericTransactionException e) {
0986:                    throw new SyncDataErrorException(
0987:                            "Commit transaction failed", e);
0988:                }
0989:
0990:                // TEST SECTION: leave false for normal use
0991:                boolean logValues = false;
0992:                if (logValues && keysToRemove.size() > 0) {
0993:                    StringBuffer toRemoveInfo = new StringBuffer();
0994:                    Iterator keysToRemoveIter = keysToRemove.iterator();
0995:                    while (keysToRemoveIter.hasNext()) {
0996:                        GenericEntity keyToRemove = (GenericEntity) keysToRemoveIter
0997:                                .next();
0998:                        toRemoveInfo.append("\n-->[");
0999:                        toRemoveInfo.append(keyToRemove
1000:                                .get(ModelEntity.STAMP_TX_FIELD));
1001:                        toRemoveInfo.append(":");
1002:                        toRemoveInfo.append(keyToRemove
1003:                                .get(ModelEntity.STAMP_FIELD));
1004:                        toRemoveInfo.append("] ");
1005:                        toRemoveInfo.append(keyToRemove);
1006:                    }
1007:                    Debug.logInfo(toRemoveInfo.toString(), module);
1008:                }
1009:
1010:                return keysToRemove;
1011:            }
1012:
1013:            public void saveResultsReportedFromDataStore()
1014:                    throws SyncDataErrorException, SyncServiceErrorException {
1015:                try {
1016:                    long runningTimeMillis = System.currentTimeMillis()
1017:                            - startDate.getTime();
1018:
1019:                    // get the total for this split
1020:                    long splitTotalTime = System.currentTimeMillis()
1021:                            - this .splitStartTime;
1022:                    if (splitTotalTime < this .perSplitMinMillis) {
1023:                        this .perSplitMinMillis = splitTotalTime;
1024:                    }
1025:                    if (splitTotalTime > this .perSplitMaxMillis) {
1026:                        this .perSplitMaxMillis = splitTotalTime;
1027:                    }
1028:
1029:                    // start the timer for the next split
1030:                    setSplitStartTime();
1031:
1032:                    // total the rows saved so far, and gather some info about them before saving
1033:                    this .totalRowsPerSplit = this .toCreateInserted
1034:                            + this .toCreateNotUpdated + this .toCreateUpdated
1035:                            + this .toStoreInserted + this .toStoreNotUpdated
1036:                            + this .toStoreUpdated + this .toRemoveAlreadyDeleted
1037:                            + this .toRemoveDeleted;
1038:                    if (this .totalRowsPerSplit < this .perSplitMinItems) {
1039:                        this .perSplitMinItems = this .totalRowsPerSplit;
1040:                    }
1041:                    if (this .totalRowsPerSplit > this .perSplitMaxItems) {
1042:                        this .perSplitMaxItems = this .totalRowsPerSplit;
1043:                    }
1044:                    this .totalRowsToCreate += this .toCreateInserted
1045:                            + this .toCreateNotUpdated + this .toCreateUpdated;
1046:                    this .totalRowsToStore += this .toStoreInserted
1047:                            + this .toStoreNotUpdated + this .toStoreUpdated;
1048:                    this .totalRowsToRemove += this .toRemoveAlreadyDeleted
1049:                            + this .toRemoveDeleted;
1050:
1051:                    // store latest result on EntitySync, ie update lastSuccessfulSynchTime, should run in own tx
1052:                    Map updateEsRunResult = dispatcher.runSync(
1053:                            "updateEntitySyncRunning", UtilMisc.toMap(
1054:                                    "entitySyncId", entitySyncId,
1055:                                    "lastSuccessfulSynchTime",
1056:                                    this .currentRunEndTime, "userLogin",
1057:                                    userLogin));
1058:
1059:                    // store result of service call on history with results so far, should run in own tx
1060:                    Map updateHistoryMap = UtilMisc
1061:                            .toMap("entitySyncId", entitySyncId, "startDate",
1062:                                    startDate, "lastSuccessfulSynchTime",
1063:                                    this .currentRunEndTime,
1064:                                    "lastCandidateEndTime", this 
1065:                                            .getNextRunEndTime(),
1066:                                    "lastSplitStartTime", new Long(
1067:                                            this .splitStartTime));
1068:                    updateHistoryMap.put("toCreateInserted", new Long(
1069:                            toCreateInserted));
1070:                    updateHistoryMap.put("toCreateUpdated", new Long(
1071:                            toCreateUpdated));
1072:                    updateHistoryMap.put("toCreateNotUpdated", new Long(
1073:                            toCreateNotUpdated));
1074:                    updateHistoryMap.put("toStoreInserted", new Long(
1075:                            toStoreInserted));
1076:                    updateHistoryMap.put("toStoreUpdated", new Long(
1077:                            toStoreUpdated));
1078:                    updateHistoryMap.put("toStoreNotUpdated", new Long(
1079:                            toStoreNotUpdated));
1080:                    updateHistoryMap.put("toRemoveDeleted", new Long(
1081:                            toRemoveDeleted));
1082:                    updateHistoryMap.put("toRemoveAlreadyDeleted", new Long(
1083:                            toRemoveAlreadyDeleted));
1084:                    updateHistoryMap.put("runningTimeMillis", new Long(
1085:                            runningTimeMillis));
1086:                    updateHistoryMap.put("totalStoreCalls", new Long(
1087:                            totalStoreCalls));
1088:                    updateHistoryMap.put("totalSplits", new Long(totalSplits));
1089:                    updateHistoryMap.put("totalRowsExported", new Long(
1090:                            totalRowsExported));
1091:                    updateHistoryMap.put("totalRowsToCreate", new Long(
1092:                            totalRowsToCreate));
1093:                    updateHistoryMap.put("totalRowsToStore", new Long(
1094:                            totalRowsToStore));
1095:                    updateHistoryMap.put("totalRowsToRemove", new Long(
1096:                            totalRowsToRemove));
1097:                    updateHistoryMap.put("perSplitMinMillis", new Long(
1098:                            perSplitMinMillis));
1099:                    updateHistoryMap.put("perSplitMaxMillis", new Long(
1100:                            perSplitMaxMillis));
1101:                    updateHistoryMap.put("perSplitMinItems", new Long(
1102:                            perSplitMinItems));
1103:                    updateHistoryMap.put("perSplitMaxItems", new Long(
1104:                            perSplitMaxItems));
1105:                    updateHistoryMap.put("userLogin", userLogin);
1106:                    Map updateEsHistRunResult = dispatcher.runSync(
1107:                            "updateEntitySyncHistory", updateHistoryMap);
1108:
1109:                    // now we have updated EntitySync and EntitySyncHistory, check both ops for errors...
1110:                    if (ServiceUtil.isError(updateEsRunResult)) {
1111:                        String errorMsg = "Error running EntitySync ["
1112:                                + entitySyncId
1113:                                + "], update of EntitySync record with lastSuccessfulSynchTime failed.";
1114:                        throw new SyncDataErrorException(errorMsg, null, null,
1115:                                updateEsRunResult, null);
1116:                    }
1117:
1118:                    if (ServiceUtil.isError(updateEsHistRunResult)) {
1119:                        String errorMsg = "Error running EntitySync ["
1120:                                + entitySyncId
1121:                                + "], update of EntitySyncHistory (startDate:["
1122:                                + startDate
1123:                                + "]) record with lastSuccessfulSynchTime and result stats failed.";
1124:                        throw new SyncDataErrorException(errorMsg, null, null,
1125:                                updateEsHistRunResult, null);
1126:                    }
1127:                } catch (GenericServiceException e) {
1128:                    throw new SyncServiceErrorException(
1129:                            "Error saving results reported from data store", e);
1130:                }
1131:            }
1132:
1133:            public void saveFinalSyncResults() throws SyncDataErrorException,
1134:                    SyncServiceErrorException {
1135:                String newStatusId = "ESR_COMPLETE";
1136:                if (this .isOfflineSync && totalRowsExported > 0) {
1137:                    newStatusId = "ESR_PENDING";
1138:                }
1139:
1140:                // the lastSuccessfulSynchTime on EntitySync will already be set, so just set status as completed
1141:                String esErrMsg = "Could not mark Entity Sync as complete, but all synchronization was successful";
1142:                try {
1143:                    Map completeEntitySyncRes = dispatcher.runSync(
1144:                            "updateEntitySyncRunning", UtilMisc.toMap(
1145:                                    "entitySyncId", entitySyncId,
1146:                                    "runStatusId", newStatusId, "userLogin",
1147:                                    userLogin));
1148:                    if (ServiceUtil.isError(completeEntitySyncRes)) {
1149:                        // what to do here? try again?
1150:                        throw new SyncDataErrorException(esErrMsg, null, null,
1151:                                completeEntitySyncRes, null);
1152:                    }
1153:                } catch (GenericServiceException e) {
1154:                    throw new SyncServiceErrorException(esErrMsg, e);
1155:                }
1156:
1157:                // if nothing moved over, remove the history record, otherwise store status
1158:                long totalRows = totalRowsToCreate + totalRowsToStore
1159:                        + totalRowsToRemove;
1160:                if (totalRows == 0) {
1161:                    String eshRemoveErrMsg = "Could not remove Entity Sync History (done becuase nothing was synced in this call), but all synchronization was successful";
1162:                    try {
1163:                        Map deleteEntitySyncHistRes = dispatcher.runSync(
1164:                                "deleteEntitySyncHistory", UtilMisc.toMap(
1165:                                        "entitySyncId", entitySyncId,
1166:                                        "startDate", startDate, "userLogin",
1167:                                        userLogin));
1168:                        if (ServiceUtil.isError(deleteEntitySyncHistRes)) {
1169:                            throw new SyncDataErrorException(eshRemoveErrMsg,
1170:                                    null, null, deleteEntitySyncHistRes, null);
1171:                        }
1172:                    } catch (GenericServiceException e) {
1173:                        throw new SyncServiceErrorException(eshRemoveErrMsg, e);
1174:                    }
1175:                } else {
1176:                    // the lastSuccessfulSynchTime on EntitySync will already be set, so just set status as completed
1177:                    String eshCompleteErrMsg = "Could not mark Entity Sync History as complete, but all synchronization was successful";
1178:                    try {
1179:                        Map completeEntitySyncHistRes = dispatcher
1180:                                .runSync("updateEntitySyncHistory", UtilMisc
1181:                                        .toMap("entitySyncId", entitySyncId,
1182:                                                "startDate", startDate,
1183:                                                "runStatusId", "ESR_COMPLETE",
1184:                                                "userLogin", userLogin));
1185:                        if (ServiceUtil.isError(completeEntitySyncHistRes)) {
1186:                            // what to do here? try again?
1187:                            throw new SyncDataErrorException(eshCompleteErrMsg,
1188:                                    null, null, completeEntitySyncHistRes, null);
1189:                        }
1190:                    } catch (GenericServiceException e) {
1191:                        throw new SyncServiceErrorException(eshCompleteErrMsg,
1192:                                e);
1193:                    }
1194:                }
1195:
1196:                if (Debug.infoOn())
1197:                    Debug.logInfo("Finished saveFinalSyncResults ["
1198:                            + entitySyncId + "]: totalRows=" + totalRows
1199:                            + ", totalRowsToCreate=" + totalRowsToCreate
1200:                            + ", totalRowsToStore=" + totalRowsToStore
1201:                            + ", totalRowsToRemove=" + totalRowsToRemove,
1202:                            module);
1203:            }
1204:
1205:            public Set makeEntityNameToUseSet() {
1206:                Set entityNameToUseSet = new HashSet();
1207:                Iterator entityModelToUseUpdateIter = this .entityModelToUseList
1208:                        .iterator();
1209:                while (entityModelToUseUpdateIter.hasNext()) {
1210:                    ModelEntity modelEntity = (ModelEntity) entityModelToUseUpdateIter
1211:                            .next();
1212:                    entityNameToUseSet.add(modelEntity.getEntityName());
1213:                }
1214:                return entityNameToUseSet;
1215:            }
1216:
1217:            /** prepare a list of all entities we want to synchronize: remove all view-entities and all entities that don't match the patterns attached to this EntitySync */
1218:            protected List makeEntityModelToUseList()
1219:                    throws GenericEntityException {
1220:                List entityModelToUseList = new LinkedList();
1221:                List entitySyncIncludes = entitySync
1222:                        .getRelated("EntitySyncInclude");
1223:
1224:                // get these ones as well, and just add them to the main list, it will have an extra field but that shouldn't hurt anything in the code below
1225:                List entitySyncGroupIncludes = entitySync
1226:                        .getRelated("EntitySyncInclGrpDetailView");
1227:                entitySyncIncludes.addAll(entitySyncGroupIncludes);
1228:
1229:                Iterator entityNameIter = delegator.getModelReader()
1230:                        .getEntityNamesIterator();
1231:                while (entityNameIter.hasNext()) {
1232:                    String entityName = (String) entityNameIter.next();
1233:                    ModelEntity modelEntity = delegator
1234:                            .getModelEntity(entityName);
1235:
1236:                    // if view-entity, throw it out
1237:                    if (modelEntity instanceof  ModelViewEntity) {
1238:                        continue;
1239:                    }
1240:
1241:                    // if it doesn't have either or both of the two update stamp fields, throw it out
1242:                    if (!modelEntity.isField(ModelEntity.STAMP_FIELD)
1243:                            || !modelEntity.isField(ModelEntity.STAMP_TX_FIELD)) {
1244:                        continue;
1245:                    }
1246:
1247:                    // if there are no includes records, always include; otherwise check each one to make sure at least one matches
1248:                    if (entitySyncIncludes.size() == 0) {
1249:                        entityModelToUseList.add(modelEntity);
1250:                    } else {
1251:                        // we have different types of include applications: ESIA_INCLUDE, ESIA_EXCLUDE, ESIA_ALWAYS
1252:                        // if we find an always we can break right there because this will always be include regardless of excludes, etc
1253:                        // if we find an include or exclude we have to finish going through the rest of them just in case there is something that overrides it (ie an exclude for an include or an always for an exclude)
1254:                        boolean matchesInclude = false;
1255:                        boolean matchesExclude = false;
1256:                        boolean matchesAlways = false;
1257:                        Iterator entitySyncIncludeIter = entitySyncIncludes
1258:                                .iterator();
1259:                        while (entitySyncIncludeIter.hasNext()) {
1260:                            GenericValue entitySyncInclude = (GenericValue) entitySyncIncludeIter
1261:                                    .next();
1262:                            String entityOrPackage = entitySyncInclude
1263:                                    .getString("entityOrPackage");
1264:                            boolean matches = false;
1265:                            if (entityName.equals(entityOrPackage)) {
1266:                                matches = true;
1267:                            } else if (modelEntity.getPackageName().startsWith(
1268:                                    entityOrPackage)) {
1269:                                matches = true;
1270:                            }
1271:
1272:                            if (matches) {
1273:                                if ("ESIA_INCLUDE".equals(entitySyncInclude
1274:                                        .getString("applEnumId"))) {
1275:                                    matchesInclude = true;
1276:                                } else if ("ESIA_EXCLUDE"
1277:                                        .equals(entitySyncInclude
1278:                                                .getString("applEnumId"))) {
1279:                                    matchesExclude = true;
1280:                                } else if ("ESIA_ALWAYS"
1281:                                        .equals(entitySyncInclude
1282:                                                .getString("applEnumId"))) {
1283:                                    matchesAlways = true;
1284:                                    break;
1285:                                }
1286:                            }
1287:                        }
1288:
1289:                        if (matchesAlways
1290:                                || (matchesInclude && !matchesExclude)) {
1291:                            // make sure this log message is not checked in uncommented:
1292:                            //Debug.log("In runEntitySync adding [" + modelEntity.getEntityName() + "] to list of Entities to sync", module);
1293:                            entityModelToUseList.add(modelEntity);
1294:                        }
1295:                    }
1296:                }
1297:
1298:                if (Debug.infoOn())
1299:                    Debug
1300:                            .logInfo(
1301:                                    "In makeEntityModelToUseList for EntitySync with ID ["
1302:                                            + entitySync.get("entitySyncId")
1303:                                            + "] syncing "
1304:                                            + entityModelToUseList.size()
1305:                                            + " entities", module);
1306:                return entityModelToUseList;
1307:            }
1308:
1309:            protected static Timestamp getCurrentRunStartTime(
1310:                    Timestamp lastSuccessfulSynchTime,
1311:                    List entityModelToUseList, GenericDelegator delegator)
1312:                    throws GenericEntityException {
1313:                // if currentRunStartTime is null, what to do? I guess iterate through all entities and find earliest tx stamp
1314:                if (lastSuccessfulSynchTime == null) {
1315:                    Timestamp currentRunStartTime = null;
1316:                    Iterator entityModelToUseIter = entityModelToUseList
1317:                            .iterator();
1318:                    while (entityModelToUseIter.hasNext()) {
1319:                        ModelEntity modelEntity = (ModelEntity) entityModelToUseIter
1320:                                .next();
1321:                        // fields to select will be PK and the STAMP_TX_FIELD, slimmed down so we don't get a ton of data back
1322:                        List fieldsToSelect = new LinkedList(modelEntity
1323:                                .getPkFieldNames());
1324:                        // find all instances of this entity with the STAMP_TX_FIELD != null, sort ascending to get lowest/oldest value first, then grab first and consider as candidate currentRunStartTime
1325:                        fieldsToSelect.add(ModelEntity.STAMP_TX_FIELD);
1326:                        EntityListIterator eli = delegator
1327:                                .findListIteratorByCondition(
1328:                                        modelEntity.getEntityName(),
1329:                                        new EntityExpr(
1330:                                                ModelEntity.STAMP_TX_FIELD,
1331:                                                EntityOperator.NOT_EQUAL, null),
1332:                                        fieldsToSelect,
1333:                                        UtilMisc
1334:                                                .toList(ModelEntity.STAMP_TX_FIELD));
1335:                        GenericValue nextValue = (GenericValue) eli.next();
1336:                        eli.close();
1337:                        if (nextValue != null) {
1338:                            Timestamp candidateTime = nextValue
1339:                                    .getTimestamp(ModelEntity.STAMP_TX_FIELD);
1340:                            if (currentRunStartTime == null
1341:                                    || candidateTime
1342:                                            .before(currentRunStartTime)) {
1343:                                currentRunStartTime = candidateTime;
1344:                            }
1345:                        }
1346:                    }
1347:                    if (Debug.infoOn())
1348:                        Debug
1349:                                .logInfo(
1350:                                        "No currentRunStartTime was stored on the EntitySync record, so searched for the earliest value and got: "
1351:                                                + currentRunStartTime, module);
1352:                    return currentRunStartTime;
1353:                } else {
1354:                    return lastSuccessfulSynchTime;
1355:                }
1356:            }
1357:
1358:            public void saveSyncErrorInfo(String runStatusId, List errorMessages) {
1359:                // set error statuses on the EntitySync and EntitySyncHistory entities
1360:                try {
1361:                    Map errorEntitySyncRes = dispatcher.runSync(
1362:                            "updateEntitySyncRunning", UtilMisc.toMap(
1363:                                    "entitySyncId", entitySyncId,
1364:                                    "runStatusId", runStatusId, "userLogin",
1365:                                    userLogin));
1366:                    if (ServiceUtil.isError(errorEntitySyncRes)) {
1367:                        errorMessages.add("Could not save error run status ["
1368:                                + runStatusId
1369:                                + "] on EntitySync with ID ["
1370:                                + entitySyncId
1371:                                + "]: "
1372:                                + errorEntitySyncRes
1373:                                        .get(ModelService.ERROR_MESSAGE));
1374:                    }
1375:                } catch (GenericServiceException e) {
1376:                    errorMessages.add("Could not save error run status ["
1377:                            + runStatusId + "] on EntitySync with ID ["
1378:                            + entitySyncId + "]: " + e.toString());
1379:                }
1380:                if (startDate != null) {
1381:                    try {
1382:                        Map errorEntitySyncHistoryRes = dispatcher.runSync(
1383:                                "updateEntitySyncHistory", UtilMisc.toMap(
1384:                                        "entitySyncId", entitySyncId,
1385:                                        "startDate", startDate, "runStatusId",
1386:                                        runStatusId, "userLogin", userLogin));
1387:                        if (ServiceUtil.isError(errorEntitySyncHistoryRes)) {
1388:                            errorMessages
1389:                                    .add("Could not save error run status ["
1390:                                            + runStatusId
1391:                                            + "] on EntitySyncHistory with ID ["
1392:                                            + entitySyncId
1393:                                            + "]: "
1394:                                            + errorEntitySyncHistoryRes
1395:                                                    .get(ModelService.ERROR_MESSAGE));
1396:                        }
1397:                    } catch (GenericServiceException e) {
1398:                        errorMessages.add("Could not save error run status ["
1399:                                + runStatusId
1400:                                + "] on EntitySyncHistory with ID ["
1401:                                + entitySyncId + ":" + startDate + "]: "
1402:                                + e.toString());
1403:                    }
1404:                }
1405:            }
1406:
1407:            // ======================== PUSH Methods ========================
1408:            public void runPushStartRunning() throws SyncDataErrorException,
1409:                    SyncServiceErrorException, SyncAbortException {
1410:                if (UtilValidate.isEmpty(targetServiceName)) {
1411:                    throw new SyncAbortException(
1412:                            "Not running EntitySync ["
1413:                                    + entitySyncId
1414:                                    + "], no targetServiceName is specified, where do we send the data?");
1415:                }
1416:
1417:                // check to see if this sync is already running, if so return error
1418:                if (this .isEntitySyncRunning()) {
1419:                    throw new SyncAbortException("Not running EntitySync ["
1420:                            + entitySyncId
1421:                            + "], an instance is already running.");
1422:                }
1423:
1424:                String markErrorMsg = "Could not start Entity Sync service, could not mark as running";
1425:                try {
1426:                    // not running, get started NOW
1427:                    // set running status on entity sync, run in its own tx
1428:                    Map startEntitySyncRes = dispatcher.runSync(
1429:                            "updateEntitySyncRunning", UtilMisc.toMap(
1430:                                    "entitySyncId", entitySyncId,
1431:                                    "runStatusId", "ESR_RUNNING", "userLogin",
1432:                                    userLogin));
1433:                    if (ModelService.RESPOND_ERROR.equals(startEntitySyncRes
1434:                            .get(ModelService.RESPONSE_MESSAGE))) {
1435:                        throw new SyncDataErrorException(markErrorMsg, null,
1436:                                null, startEntitySyncRes, null);
1437:                    }
1438:                } catch (GenericServiceException e) {
1439:                    throw new SyncServiceErrorException(markErrorMsg, e);
1440:                }
1441:
1442:                // finally create the initial history record
1443:                this .createInitialHistory();
1444:            }
1445:
1446:            public long setTotalRowCounts(ArrayList valuesToCreate,
1447:                    ArrayList valuesToStore, List keysToRemove) {
1448:                this .totalRowsToCreate = valuesToCreate.size();
1449:                this .totalRowsToStore = valuesToStore.size();
1450:                this .totalRowsToRemove = keysToRemove.size();
1451:                this .totalRowsPerSplit = this .totalRowsToCreate
1452:                        + this .totalRowsToStore + this .totalRowsToRemove;
1453:                return this .totalRowsPerSplit;
1454:            }
1455:
1456:            public void runPushSendData(ArrayList valuesToCreate,
1457:                    ArrayList valuesToStore, List keysToRemove)
1458:                    throws SyncOtherErrorException, SyncServiceErrorException {
1459:                // grab the totals for this data
1460:                this .setTotalRowCounts(valuesToCreate, valuesToStore,
1461:                        keysToRemove);
1462:
1463:                // call service named on EntitySync, IFF there is actually data to send over
1464:                if (this .totalRowsPerSplit > 0) {
1465:                    Map targetServiceMap = UtilMisc.toMap("entitySyncId",
1466:                            entitySyncId, "valuesToCreate", valuesToCreate,
1467:                            "valuesToStore", valuesToStore, "keysToRemove",
1468:                            keysToRemove, "userLogin", userLogin);
1469:                    if (UtilValidate.isNotEmpty(targetDelegatorName)) {
1470:                        targetServiceMap.put("delegatorName",
1471:                                targetDelegatorName);
1472:                    }
1473:                    String serviceErrorMsg = "Error running EntitySync ["
1474:                            + entitySyncId + "], call to store service ["
1475:                            + targetServiceName + "] failed.";
1476:                    try {
1477:                        Map remoteStoreResult = dispatcher.runSync(
1478:                                targetServiceName, targetServiceMap);
1479:                        if (ServiceUtil.isError(remoteStoreResult)) {
1480:                            throw new SyncOtherErrorException(serviceErrorMsg,
1481:                                    null, null, remoteStoreResult, null);
1482:                        }
1483:
1484:                        this .totalStoreCalls++;
1485:
1486:                        long toCreateInsertedCur = remoteStoreResult
1487:                                .get("toCreateInserted") == null ? 0
1488:                                : ((Long) remoteStoreResult
1489:                                        .get("toCreateInserted")).longValue();
1490:                        long toCreateUpdatedCur = remoteStoreResult
1491:                                .get("toCreateUpdated") == null ? 0
1492:                                : ((Long) remoteStoreResult
1493:                                        .get("toCreateUpdated")).longValue();
1494:                        long toCreateNotUpdatedCur = remoteStoreResult
1495:                                .get("toCreateNotUpdated") == null ? 0
1496:                                : ((Long) remoteStoreResult
1497:                                        .get("toCreateNotUpdated")).longValue();
1498:                        long toStoreInsertedCur = remoteStoreResult
1499:                                .get("toStoreInserted") == null ? 0
1500:                                : ((Long) remoteStoreResult
1501:                                        .get("toStoreInserted")).longValue();
1502:                        long toStoreUpdatedCur = remoteStoreResult
1503:                                .get("toStoreUpdated") == null ? 0
1504:                                : ((Long) remoteStoreResult
1505:                                        .get("toStoreUpdated")).longValue();
1506:                        long toStoreNotUpdatedCur = remoteStoreResult
1507:                                .get("toStoreNotUpdated") == null ? 0
1508:                                : ((Long) remoteStoreResult
1509:                                        .get("toStoreNotUpdated")).longValue();
1510:                        long toRemoveDeletedCur = remoteStoreResult
1511:                                .get("toRemoveDeleted") == null ? 0
1512:                                : ((Long) remoteStoreResult
1513:                                        .get("toRemoveDeleted")).longValue();
1514:                        long toRemoveAlreadyDeletedCur = remoteStoreResult
1515:                                .get("toRemoveAlreadyDeleted") == null ? 0
1516:                                : ((Long) remoteStoreResult
1517:                                        .get("toRemoveAlreadyDeleted"))
1518:                                        .longValue();
1519:
1520:                        this .toCreateInserted += toCreateInsertedCur;
1521:                        this .toCreateUpdated += toCreateUpdatedCur;
1522:                        this .toCreateNotUpdated += toCreateNotUpdatedCur;
1523:                        this .toStoreInserted += toStoreInsertedCur;
1524:                        this .toStoreUpdated += toStoreUpdatedCur;
1525:                        this .toStoreNotUpdated += toStoreNotUpdatedCur;
1526:                        this .toRemoveDeleted += toRemoveDeletedCur;
1527:                        this .toRemoveAlreadyDeleted += toRemoveAlreadyDeletedCur;
1528:                    } catch (GenericServiceException e) {
1529:                        throw new SyncServiceErrorException(serviceErrorMsg, e);
1530:                    }
1531:                }
1532:            }
1533:
1534:            // ======================== PULL Methods ========================
1535:            public void runPullStartOrRestoreSavedResults()
1536:                    throws SyncDataErrorException, SyncServiceErrorException,
1537:                    SyncAbortException {
1538:                // if EntitySync.statusId is ESR_RUNNING, make sure startDate matches EntitySync.lastHistoryStartDate; or return error
1539:                if (isEntitySyncRunning() && this .startDate == null) {
1540:                    throw new SyncAbortException(
1541:                            "Not running EntitySync ["
1542:                                    + entitySyncId
1543:                                    + "], an instance is already running and no startDate for the current run was passed.");
1544:                }
1545:
1546:                if (this .startDate == null) {
1547:                    // get it started!
1548:                    String markErrorMsg = "Could not start Entity Sync service, could not mark as running";
1549:                    try {
1550:                        // not running, get started NOW
1551:                        // set running status on entity sync, run in its own tx
1552:                        Map startEntitySyncRes = dispatcher.runSync(
1553:                                "updateEntitySyncRunning", UtilMisc.toMap(
1554:                                        "entitySyncId", entitySyncId,
1555:                                        "runStatusId", "ESR_RUNNING",
1556:                                        "userLogin", userLogin));
1557:                        if (ModelService.RESPOND_ERROR
1558:                                .equals(startEntitySyncRes
1559:                                        .get(ModelService.RESPONSE_MESSAGE))) {
1560:                            throw new SyncDataErrorException(markErrorMsg,
1561:                                    null, null, startEntitySyncRes, null);
1562:                        }
1563:                    } catch (GenericServiceException e) {
1564:                        throw new SyncServiceErrorException(markErrorMsg, e);
1565:                    }
1566:
1567:                    // finally create the initial history record
1568:                    this .createInitialHistory();
1569:                    this .setSplitStartTime();
1570:                } else {
1571:                    try {
1572:                        // set the latest values from the EntitySyncHistory, based on the values on the EntitySync
1573:                        GenericValue entitySyncHistory = delegator
1574:                                .findByPrimaryKey("EntitySyncHistory", UtilMisc
1575:                                        .toMap("entitySyncId", entitySyncId,
1576:                                                "startDate", startDate));
1577:                        this .toCreateInserted = UtilMisc
1578:                                .toLong(entitySyncHistory
1579:                                        .getLong("toCreateInserted"));
1580:                        this .toCreateUpdated = UtilMisc
1581:                                .toLong(entitySyncHistory
1582:                                        .getLong("toCreateUpdated"));
1583:                        this .toCreateNotUpdated = UtilMisc
1584:                                .toLong(entitySyncHistory
1585:                                        .getLong("toCreateNotUpdated"));
1586:
1587:                        this .toStoreInserted = UtilMisc
1588:                                .toLong(entitySyncHistory
1589:                                        .getLong("toStoreInserted"));
1590:                        this .toStoreUpdated = UtilMisc.toLong(entitySyncHistory
1591:                                .getLong("toStoreUpdated"));
1592:                        this .toStoreNotUpdated = UtilMisc
1593:                                .toLong(entitySyncHistory
1594:                                        .getLong("toStoreNotUpdated"));
1595:
1596:                        this .toRemoveDeleted = UtilMisc
1597:                                .toLong(entitySyncHistory
1598:                                        .getLong("toRemoveDeleted"));
1599:                        this .toRemoveAlreadyDeleted = UtilMisc
1600:                                .toLong(entitySyncHistory
1601:                                        .getLong("toRemoveAlreadyDeleted"));
1602:
1603:                        this .totalStoreCalls = UtilMisc
1604:                                .toLong(entitySyncHistory
1605:                                        .getLong("totalStoreCalls"));
1606:                        this .totalSplits = UtilMisc.toLong(entitySyncHistory
1607:                                .getLong("totalSplits"));
1608:                        this .totalRowsToCreate = UtilMisc
1609:                                .toLong(entitySyncHistory
1610:                                        .getLong("totalRowsToCreate"));
1611:                        this .totalRowsToStore = UtilMisc
1612:                                .toLong(entitySyncHistory
1613:                                        .getLong("totalRowsToStore"));
1614:                        this .totalRowsToRemove = UtilMisc
1615:                                .toLong(entitySyncHistory
1616:                                        .getLong("totalRowsToRemove"));
1617:
1618:                        this .perSplitMinMillis = UtilMisc
1619:                                .toLong(entitySyncHistory
1620:                                        .getLong("perSplitMinMillis"));
1621:                        this .perSplitMaxMillis = UtilMisc
1622:                                .toLong(entitySyncHistory
1623:                                        .getLong("perSplitMaxMillis"));
1624:                        this .perSplitMinItems = UtilMisc
1625:                                .toLong(entitySyncHistory
1626:                                        .getLong("perSplitMinItems"));
1627:                        this .perSplitMaxItems = UtilMisc
1628:                                .toLong(entitySyncHistory
1629:                                        .getLong("perSplitMaxItems"));
1630:
1631:                        this .splitStartTime = UtilMisc.toLong(entitySyncHistory
1632:                                .getLong("lastSplitStartTime"));
1633:                    } catch (GenericEntityException e) {
1634:                        throw new SyncDataErrorException(
1635:                                "Error getting existing EntitySyncHistory values",
1636:                                e);
1637:                    }
1638:
1639:                    // got the previous values, now add to them with the values from the context...
1640:                    this .toCreateInserted += UtilMisc.toLong(this .context
1641:                            .get("toCreateInserted"));
1642:                    this .toCreateUpdated += UtilMisc.toLong(this .context
1643:                            .get("toCreateUpdated"));
1644:                    this .toCreateNotUpdated += UtilMisc.toLong(this .context
1645:                            .get("toCreateNotUpdated"));
1646:                    this .toStoreInserted += UtilMisc.toLong(this .context
1647:                            .get("toStoreInserted"));
1648:                    this .toStoreUpdated += UtilMisc.toLong(this .context
1649:                            .get("toStoreUpdated"));
1650:                    this .toStoreNotUpdated += UtilMisc.toLong(this .context
1651:                            .get("toStoreNotUpdated"));
1652:                    this .toRemoveDeleted += UtilMisc.toLong(this .context
1653:                            .get("toRemoveDeleted"));
1654:                    this .toRemoveAlreadyDeleted += UtilMisc.toLong(this .context
1655:                            .get("toRemoveAlreadyDeleted"));
1656:
1657:                    this .totalStoreCalls++;
1658:
1659:                    this .saveResultsReportedFromDataStore();
1660:                }
1661:            }
1662:
1663:            // ======================== OFFLINE Methods ========================
1664:            public void runOfflineStartRunning() throws SyncDataErrorException,
1665:                    SyncServiceErrorException, SyncAbortException {
1666:                // check to see if this sync is already running, if so return error
1667:                if (this .isEntitySyncRunning()) {
1668:                    throw new SyncAbortException("Not running EntitySync ["
1669:                            + entitySyncId
1670:                            + "], an instance is already running.");
1671:                }
1672:
1673:                // flag this context as offline
1674:                this .isOfflineSync = true;
1675:
1676:                String markErrorMsg = "Could not start Entity Sync service, could not mark as running";
1677:                try {
1678:                    // not running, get started NOW
1679:                    // set running status on entity sync, run in its own tx
1680:                    Map startEntitySyncRes = dispatcher.runSync(
1681:                            "updateEntitySyncRunning", UtilMisc.toMap(
1682:                                    "entitySyncId", entitySyncId,
1683:                                    "runStatusId", "ESR_RUNNING",
1684:                                    "preOfflineSynchTime",
1685:                                    this .lastSuccessfulSynchTime, "userLogin",
1686:                                    userLogin));
1687:                    if (ModelService.RESPOND_ERROR.equals(startEntitySyncRes
1688:                            .get(ModelService.RESPONSE_MESSAGE))) {
1689:                        throw new SyncDataErrorException(markErrorMsg, null,
1690:                                null, startEntitySyncRes, null);
1691:                    }
1692:                } catch (GenericServiceException e) {
1693:                    throw new SyncServiceErrorException(markErrorMsg, e);
1694:                }
1695:
1696:                // finally create the initial history record
1697:                this .createInitialHistory();
1698:            }
1699:
1700:            public void runSaveOfflineSyncInfo(long rowsInSplit)
1701:                    throws SyncDataErrorException, SyncServiceErrorException,
1702:                    SyncAbortException {
1703:                this .totalRowsExported += rowsInSplit;
1704:                this .saveResultsReportedFromDataStore();
1705:            }
1706:
1707:            /**
1708:             * Static method to obtain a list of entity names which will be synchronized
1709:             */
1710:            public static Set getEntitySyncModelNamesToUse(
1711:                    LocalDispatcher dispatcher, String entitySyncId)
1712:                    throws SyncDataErrorException, SyncAbortException {
1713:                DispatchContext dctx = dispatcher.getDispatchContext();
1714:                EntitySyncContext ctx = new EntitySyncContext(dctx, UtilMisc
1715:                        .toMap("entitySyncId", entitySyncId));
1716:                return ctx.makeEntityNameToUseSet();
1717:            }
1718:
1719:            /** This class signifies an abort condition, so the state and such of the EntitySync value in the datasource should not be changed */
1720:            public static class SyncAbortException extends
1721:                    GeneralServiceException {
1722:                public SyncAbortException() {
1723:                    super ();
1724:                }
1725:
1726:                public SyncAbortException(String str) {
1727:                    super (str);
1728:                }
1729:
1730:                public SyncAbortException(String str, Throwable nested) {
1731:                    super (str, nested);
1732:                }
1733:
1734:                public SyncAbortException(Throwable nested) {
1735:                    super (nested);
1736:                }
1737:
1738:                public SyncAbortException(String str, List errorMsgList,
1739:                        Map errorMsgMap, Map nestedServiceResult,
1740:                        Throwable nested) {
1741:                    super (str, errorMsgList, errorMsgMap, nestedServiceResult,
1742:                            nested);
1743:                }
1744:            }
1745:
1746:            public static abstract class SyncErrorException extends
1747:                    GeneralServiceException {
1748:                public SyncErrorException() {
1749:                    super ();
1750:                }
1751:
1752:                public SyncErrorException(String str) {
1753:                    super (str);
1754:                }
1755:
1756:                public SyncErrorException(String str, Throwable nested) {
1757:                    super (str, nested);
1758:                }
1759:
1760:                public SyncErrorException(Throwable nested) {
1761:                    super (nested);
1762:                }
1763:
1764:                public SyncErrorException(String str, List errorMsgList,
1765:                        Map errorMsgMap, Map nestedServiceResult,
1766:                        Throwable nested) {
1767:                    super (str, errorMsgList, errorMsgMap, nestedServiceResult,
1768:                            nested);
1769:                }
1770:
1771:                public abstract void saveSyncErrorInfo(EntitySyncContext esc);
1772:            }
1773:
1774:            /** This class signifies an error condition, so the state of the EntitySync value and the EntitySyncHistory value in the datasource should be changed to reflect the error */
1775:            public static class SyncOtherErrorException extends
1776:                    SyncErrorException {
1777:                public SyncOtherErrorException() {
1778:                    super ();
1779:                }
1780:
1781:                public SyncOtherErrorException(String str) {
1782:                    super (str);
1783:                }
1784:
1785:                public SyncOtherErrorException(String str, Throwable nested) {
1786:                    super (str, nested);
1787:                }
1788:
1789:                public SyncOtherErrorException(Throwable nested) {
1790:                    super (nested);
1791:                }
1792:
1793:                public SyncOtherErrorException(String str, List errorMsgList,
1794:                        Map errorMsgMap, Map nestedServiceResult,
1795:                        Throwable nested) {
1796:                    super (str, errorMsgList, errorMsgMap, nestedServiceResult,
1797:                            nested);
1798:                }
1799:
1800:                public void saveSyncErrorInfo(EntitySyncContext esc) {
1801:                    if (esc != null) {
1802:                        List errorList = new LinkedList();
1803:                        esc.saveSyncErrorInfo("ESR_OTHER_ERROR", errorList);
1804:                        this .addErrorMessages(errorList);
1805:                    }
1806:                }
1807:            }
1808:
1809:            /** This class signifies an error condition, so the state of the EntitySync value and the EntitySyncHistory value in the datasource should be changed to reflect the error */
1810:            public static class SyncDataErrorException extends
1811:                    SyncErrorException {
1812:                public SyncDataErrorException() {
1813:                    super ();
1814:                }
1815:
1816:                public SyncDataErrorException(String str) {
1817:                    super (str);
1818:                }
1819:
1820:                public SyncDataErrorException(String str, Throwable nested) {
1821:                    super (str, nested);
1822:                }
1823:
1824:                public SyncDataErrorException(Throwable nested) {
1825:                    super (nested);
1826:                }
1827:
1828:                public SyncDataErrorException(String str, List errorMsgList,
1829:                        Map errorMsgMap, Map nestedServiceResult,
1830:                        Throwable nested) {
1831:                    super (str, errorMsgList, errorMsgMap, nestedServiceResult,
1832:                            nested);
1833:                }
1834:
1835:                public void saveSyncErrorInfo(EntitySyncContext esc) {
1836:                    if (esc != null) {
1837:                        List errorList = new LinkedList();
1838:                        esc.saveSyncErrorInfo("ESR_DATA_ERROR", errorList);
1839:                        this .addErrorMessages(errorList);
1840:                    }
1841:                }
1842:            }
1843:
1844:            /** This class signifies an error condition, so the state of the EntitySync value and the EntitySyncHistory value in the datasource should be changed to reflect the error */
1845:            public static class SyncServiceErrorException extends
1846:                    SyncErrorException {
1847:                public SyncServiceErrorException() {
1848:                    super ();
1849:                }
1850:
1851:                public SyncServiceErrorException(String str) {
1852:                    super (str);
1853:                }
1854:
1855:                public SyncServiceErrorException(String str, Throwable nested) {
1856:                    super (str, nested);
1857:                }
1858:
1859:                public SyncServiceErrorException(Throwable nested) {
1860:                    super (nested);
1861:                }
1862:
1863:                public SyncServiceErrorException(String str, List errorMsgList,
1864:                        Map errorMsgMap, Map nestedServiceResult,
1865:                        Throwable nested) {
1866:                    super (str, errorMsgList, errorMsgMap, nestedServiceResult,
1867:                            nested);
1868:                }
1869:
1870:                public void saveSyncErrorInfo(EntitySyncContext esc) {
1871:                    if (esc != null) {
1872:                        List errorList = new LinkedList();
1873:                        esc.saveSyncErrorInfo("ESR_SERVICE_ERROR", errorList);
1874:                        this.addErrorMessages(errorList);
1875:                    }
1876:                }
1877:            }
1878:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.