Java tutorial
/* * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-2.1.html * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Contributors: * thibaud */ package org.nuxeo.cm.demo; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.datademo.RandomFirstLastNames; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.core.schema.SchemaManager; import org.nuxeo.ecm.core.schema.types.Schema; import org.nuxeo.ecm.core.uidgen.UIDSequencer; import org.nuxeo.ecm.platform.dublincore.listener.DublinCoreListener; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.transaction.TransactionHelper; /** * @author Thibaud Arguillere * @since 5.9.2 This class takes the InsuranceClaim and update them so the demo looks better. For example, when the data * is reset every night from the same original backup, you find yourself with claims created beginning of 2013 * while you are in 2014 and you want stats from "the last month" => you will find nothing (or just the 1-2 cases * you created during the demo) We update all data and set the dates to a random date form the last 3 months, * with a bit more for the last month. ============================================================ IMPORTANT * ============================================================ 1/ We don't want workflows to be started, mails * to be sent, etc. So, to avoid some event handlers defined in the Studio project to be triggered, we use the * following strategy: - The code defines a contextData property for the document: * oneDoc.putContextData("UpdatingData_NoEventPlease", true); - In the project, the event handlers that must * *not* be triggered when updating the data have the following EL condition: * Document.doc.getContextData("UpdatingData_NoEventPlease") == null 2/ We create (if needed) a "nice claim" ( a * claim with more info, so we can use the Template Rendering plug-in to display the case as pdf. => THE CODE * CREATES IT IN "/Insurance Claims/Claims" => These domain/folder *mus* exist. * ============================================================ THIS CODE HANDLES THE FOLLOWING: * ============================================================ dc:created Half of the claims in the past month * If a claim is "Archived", creation date is set between 15-30 days ago The other half: 2-3 months ago * dc:modified dc:lastContributor dc:contributors These one, thanks to the act that it is possible to disable the * dublincore listener. In this code, we disable it for each document: * oneDoc.putContextData(DublinCoreListener.DISABLE_DUBLINCORE_LISTENER, true); (this is a super great feature) * incl:contract_start/incl:contract_end One year, and "today" is in this range incl:date_opened is the creation * data incl:due_date Same as Studio rule (cf. chain IC-AC-Claim-OnDocumentCreated) incl:date_closed Only if the * claim is archived Set to 0-5 days ago dc:title Updated to reflect the changes in the creation date WARNING: * the path cannot be changed, but it is ok. ============================================================ IT DOES * NOT HANDLE: ============================================================ Dates of workflows (due dates of * tasks for example) ================= WARNING WARNING WARNING WARNING WARNING ================= About changing * the lifecycle state, we are using code that bypasses a lot of controls (so we avoid event sent, etc.). * ============================================================================ */ public class UpdateDemoData { private static final Log log = LogFactory.getLog(UpdateDemoData.class); static protected final int kSAVE_SESSION_MODULO = 25; // Acting as a constant. Not handling "deleted". static protected Map<String, Integer> _kSTATES = null; static protected final int kLFS_RECEIVED = 0; static protected final int kLFS_CHECK_CONTRACT = 1; static protected final int kLFS_OPENED = 2; static protected final int kLFS_COMPLETED = 3; static protected final int kLFS_EXPERT_ON_SITE_NEEDED = 4; static protected final int kLFS_EVALUATED = 5; static protected final int kLFS_DECISION_MADE = 6; static protected final int kLFS_ARCHIVED = 7; // This list should be loaded dynamically static protected final String[] kUSERS = { "john", "john", "john", "john", "kate", "kate", "kate", "alan", "julie", "julie", "mike" }; static protected final int kMAX_FOR_USERS_RANDOM = kUSERS.length - 1; static private final String kNICE_CLAIM_PARENT_PATH = "/Insurance Claims/Claims"; static private final String kNICE_CLAIM_FIELD = "dc:format"; static private final String kNICE_CLAIM_FIELD_VALUE = "Nice claim for template rendering"; static private final String[] kCITIES = { "New York", "New York", "New York", "Los Angeles", "Los Angeles", "Atlanta", "Seattle", "Boston", "Orlando" }; static private final int kCITIES_MAX = kCITIES.length - 1; static private final String[] kCOUNTRIES = { "US", "US", "US", "US", "US", "GB", "GB", "GB", "GB", "GB", "GB", "GB", "GB", "GB", "GB", "GB", "FR", "FR", "FR", "FR", "FR", "FR", "ES", "ES", "ES", "IT", "IT", "DE", "DE", "DE", "DE", "DE", "DE", "DE", "DE", "CH", "AT", "GR", "PT", "IS", "NO", "NO", "SE", "SE", "PL", "IE" }; static private final int kCOUNTRIES_MAX = kCOUNTRIES.length - 1; // Based on "AccidentTypologie" vocabulary static private final String[] ACC_TYPOLOGY = { "City/Parking", "City/Parking", "City/Parking", "City/Parking", "City/Parking", "City/Crossroads", "City/Crossroads", "City/Crossroads", "City/Avenue", "Country/Tunnel", "Country/Tunnel", "Country/Tunnel", "Country/Traffic Circle", "Highway/Ramp Access", "Highway/Ramp Access", "Highway/Ramp Access", "Highway/Gas Station", "Highway/Gas Station" }; static private final int ACC_TYPOLOGY_MAX = ACC_TYPOLOGY.length - 1; // WARNING: UPDATE THIS citiesAndStates IF YOU CHANGE kCITIES static private HashMap<String, String> citiesAndStates; protected DateFormat _yyyyMMdd = new SimpleDateFormat("yyyy-MM-dd"); protected Calendar _today = Calendar.getInstance(); protected CoreSession _session; protected int _saveCounter = 0; RandomFirstLastNames randomPeopleNames; // SHould be temporary, the time for everybody to upgrade to latest Studio project boolean hasAccidentTypology = false; public UpdateDemoData(CoreSession inSession) throws IOException { _session = inSession; _setup(); } public void run() throws Exception { TransactionHelper.commitOrRollbackTransaction(); TransactionHelper.startTransaction(); _UpdateData(); TransactionHelper.commitOrRollbackTransaction(); TransactionHelper.startTransaction(); } private int _randomInt(int inMin, int inMax) { // No error check here return inMin + (int) (Math.random() * ((inMax - inMin) + 1)); } private void _saveDocument(DocumentModel inDoc) throws NuxeoException { _session.saveDocument(inDoc); if ((++_saveCounter % kSAVE_SESSION_MODULO) == 0) { _doLog("Commiting the last " + kSAVE_SESSION_MODULO + " InsuranceClaim (and their children.) Total InsuranceClaim handled: " + _saveCounter); TransactionHelper.commitOrRollbackTransaction(); TransactionHelper.startTransaction(); } } protected void _setup() throws IOException { _kSTATES = new HashMap<String, Integer>(); _kSTATES.put("received", kLFS_RECEIVED); _kSTATES.put("checkcontract", kLFS_CHECK_CONTRACT); _kSTATES.put("opened", kLFS_OPENED); _kSTATES.put("completed", kLFS_COMPLETED); _kSTATES.put("expertonsiteneeded", kLFS_EXPERT_ON_SITE_NEEDED); _kSTATES.put("evaluated", kLFS_EVALUATED); _kSTATES.put("decisionmade", kLFS_DECISION_MADE); _kSTATES.put("archived", kLFS_ARCHIVED); citiesAndStates = new HashMap<String, String>(); citiesAndStates.put("New York", "NY"); citiesAndStates.put("Los Angeles", "CA"); citiesAndStates.put("Atlanta", "GA"); citiesAndStates.put("Seattle", "WA"); citiesAndStates.put("Boston", "MA"); citiesAndStates.put("Orlando", "FL"); randomPeopleNames = RandomFirstLastNames.getInstance(); SchemaManager sm = Framework.getLocalService(SchemaManager.class); Schema schema = sm.getSchema("InsuranceClaim"); hasAccidentTypology = schema.getField("typology") != null; log.warn("Has incl:typology field: " + hasAccidentTypology); } protected int _lifecycleStateStrToInt(String inLCS) { Integer val = _kSTATES.get(inLCS); return val == null ? -1 : val; } // A wrapper. Someday, we should change this to it's own log file // In the meantime, just use "warn", because we don't want to // stop the server, change log level to debug, start server, etc. protected void _doLog(String inWhat) { log.warn(inWhat); } private Calendar _buildDate(Calendar inDate, int inDays) { Calendar d = (Calendar) inDate.clone(); d.add(Calendar.DATE, inDays); if (d.after(_today)) { d = (Calendar) _today.clone(); } return d; } private Calendar _buildDate(Calendar inDate, int inDays, boolean inOkIfAfterToday) { Calendar d = (Calendar) inDate.clone(); d.add(Calendar.DATE, inDays); if (d.after(_today) && !inOkIfAfterToday) { d = (Calendar) _today.clone(); } return d; } // Title update (replace 20130903 - for example - with the correct date) // Unfortunately, we have some cases which start with YYYY-MM-DD (instead // of the dashes-free version, YYYYMMDD), so we must handle that (and remove // dashes) // Does not save the document, just update the fields private void _updateTitle(DocumentModel inDoc, String dateStr) throws NuxeoException { String title = (String) inDoc.getPropertyValue("dc:title"); if (title.charAt(4) == '-') { title = dateStr.replaceAll("-", "") + title.substring(7); } else { title = dateStr.replaceAll("-", "") + title.substring(8); } inDoc.setPropertyValue("dc:title", title); inDoc.setPropertyValue("incl:incident_id", title); } // Does not save the document private void _updateModificationInfo(DocumentModel inDoc, String inUser, Calendar inDate) throws NuxeoException { inDoc.setPropertyValue("dc:lastContributor", inUser); // Handling the list of contributors: The following is a // copy/paste from... // nuxeo-platform-dublincore/src/main/java/org/nuxeo/ecm/ // platform/dublincore/service/DublinCoreStorageService.java // ... with very little change (no try-catch for example) String[] contributorsArray; contributorsArray = (String[]) inDoc.getProperty("dublincore", "contributors"); List<String> contributorsList = new ArrayList<String>(); if (contributorsArray != null && contributorsArray.length > 0) { contributorsList = Arrays.asList(contributorsArray); // make it resizable contributorsList = new ArrayList<String>(contributorsList); } if (!contributorsList.contains(inUser)) { contributorsList.add(inUser); String[] contributorListIn = new String[contributorsList.size()]; contributorsList.toArray(contributorListIn); inDoc.setProperty("dublincore", "contributors", contributorListIn); inDoc.setPropertyValue("dc:contributors", contributorListIn); } inDoc.setPropertyValue("dc:modified", inDate); } /* * Just to try-catch on Thread.sleep, so we don't have to throw or catch an InterruptedException */ private void _wait(long inMs) { try { Thread.sleep(inMs); } catch (InterruptedException e) { // Should never be here: This thread is not the main threda. No // chance! } } /* * Update the demo data */ private void _UpdateData() throws Exception { // First, we want to delete the "Nice Claim". Because updating it is // useless // and also because it generates some "ausitCoreListener" error about // the // thing not finding the document _niceClaimDelete(); // Now, get all the claims String nxql = "SELECT * FROM InsuranceClaim"; nxql += " WHERE ecm:isCheckedInVersion = 0"; nxql += " AND ecm:currentLifeCycleState != 'deleted'"; DocumentModelList allDocs = _session.query(nxql); _doLog("Update demo data: " + allDocs.size() + "document(s) to update"); // ============================================================ // Update existing cases // ============================================================ for (DocumentModel oneDoc : allDocs) { Calendar aDate, startDate, creationDate, modifDate; String creator; updateLifecycleState(oneDoc); int lfs = _lifecycleStateStrToInt(oneDoc.getCurrentLifeCycleState().toLowerCase()); String creationDateStr; // Half in previous month creationDate = (Calendar) _today.clone(); switch (lfs) { case kLFS_ARCHIVED: creationDate.add(Calendar.DATE, _randomInt(30, 90) * -1); break; case kLFS_RECEIVED: creationDate.add(Calendar.DATE, _randomInt(2, 20) * -1); break; case kLFS_CHECK_CONTRACT: creationDate.add(Calendar.DATE, _randomInt(5, 30) * -1); break; case kLFS_OPENED: creationDate.add(Calendar.DATE, _randomInt(20, 40) * -1); break; case kLFS_COMPLETED: creationDate.add(Calendar.DATE, _randomInt(20, 40) * -1); break; case kLFS_EVALUATED: creationDate.add(Calendar.DATE, _randomInt(50, 80) * -1); break; case kLFS_DECISION_MADE: creationDate.add(Calendar.DATE, _randomInt(30, 90) * -1); break; default: creationDate.add(Calendar.DATE, _randomInt(31, 90) * -1); break; } creationDateStr = _yyyyMMdd.format(creationDate.getTime()); oneDoc.setPropertyValue("dc:created", creationDate); oneDoc.setPropertyValue("incl:date_received", creationDate); // We don't want to build the exact same due_date as the Studio // project does // because we want mixed due_date for our JavaScript dashboard /* * String claimKind = (String) oneDoc.getPropertyValue("incl:incident_kind"); * if(claimKind.equals("building-fire")) { aDate = _buildDate(creationDate, 90); } else * if(claimKind.equals("breakdown")) { aDate = _buildDate(creationDate, 10); } else { aDate = * _buildDate(creationDate, 30); } */ // Say about 25% are past due (not always: If the case is closed, // archived // the dashboard does not even look at the due_date) if (_randomInt(1, 4) == 1) { aDate = _buildDate(_today, _randomInt(1, 10) * -1); } else { aDate = _buildDate(_today, _randomInt(1, 30), true); } oneDoc.setPropertyValue("incl:due_date", aDate); creator = kUSERS[_randomInt(0, kMAX_FOR_USERS_RANDOM)]; oneDoc.setPropertyValue("dc:creator", creator); // Update the title and incident_id _updateTitle(oneDoc, creationDateStr); // Opening date of the case to this date, eventually 1-3 days before // "incl:date_received" startDate = (Calendar) creationDate.clone(); int daysBefore = _randomInt(0, 3); if (daysBefore != 0) { startDate.add(Calendar.DATE, daysBefore * -1); } oneDoc.setPropertyValue("incl:incident_date", startDate); // Update contract start/end date. Say a range of one year with // today // in this range aDate = _buildDate(creationDate, _randomInt(30, 180) * -1); oneDoc.setPropertyValue("incl:contract_start", aDate); aDate.add(Calendar.DATE, 365); oneDoc.setPropertyValue("incl:contract_end", aDate); // If the case is closed, change the date of the closing // We also set the modifDate here because it is == closing date if // accurate // For Kibana stats, have modif dates in the last 3 months // IMPORTANT: This will not be accurate with the creation date, // it may happen the creation date becomes > modification modifDate = _buildDate(_today, _randomInt(0, 90) * -1); /* * if (lfs == kLFS_ARCHIVED) { aDate = _buildDate(_today, _randomInt(5, 90) * -1); * oneDoc.setPropertyValue("incl:date_closed", aDate); modifDate = (Calendar) aDate.clone(); } else { // Let * say it was modified recently... modifDate = _buildDate(_today, _randomInt(0, 10) * -1); } */ _updateModificationInfo(oneDoc, kUSERS[_randomInt(0, kMAX_FOR_USERS_RANDOM)], modifDate); // Update first/last names oneDoc.setPropertyValue("pein:first_name", randomPeopleNames.getAFirstName(RandomFirstLastNames.GENDER.ANY)); oneDoc.setPropertyValue("pein:last_name", randomPeopleNames.getALastName()); String city = kCITIES[_randomInt(0, kCITIES_MAX)]; oneDoc.setPropertyValue("incl:incident_city", city); oneDoc.setPropertyValue("incl:incident_us_state", citiesAndStates.get(city)); // Yes the country is totally random and does not match the city or state; it's just a demo! :) String country = kCOUNTRIES[_randomInt(0, kCOUNTRIES_MAX)]; oneDoc.setPropertyValue("incl:incident_country", country); if (hasAccidentTypology) { String kind = (String) oneDoc.getPropertyValue("incl:incident_kind"); if (kind != null && kind.equals("accident")) { oneDoc.setPropertyValue("incl:typology", ACC_TYPOLOGY[_randomInt(0, ACC_TYPOLOGY_MAX)]); } } // Now update some info of the children, if any DocumentModelList children = _session.getChildren(oneDoc.getRef()); for (DocumentModel oneChild : children) { // Did not dig into the problem, but calling... // oneChild.setPropertyValue("dc:created", creationDate); // ...leads to a "property not found" error. The workaround // I found was about using setProperty() instead. oneChild.setProperty("dublincore", "created", creationDate); oneChild.setProperty("dublincore", "creator", creator); aDate = _buildDate(creationDate, _randomInt(0, 10)); oneChild.setProperty("dublincore", "modified", aDate); oneChild.setProperty("dublincore", "lastContributor", kUSERS[_randomInt(0, kMAX_FOR_USERS_RANDOM)]); _session.saveDocument(oneChild); // Don't want to handle MailFolder (which is, actually, not used // in the demo) // We also don't handle recursivity, sub-sub-folders, etc. if (oneChild.isFolder() && oneChild.getType().toLowerCase().indexOf("mail") < 0) { DocumentModelList grandChildren = _session.getChildren(oneChild.getRef()); for (DocumentModel oneGrandChild : grandChildren) { if (oneChild.isFolder()) { oneGrandChild.setPropertyValue("dc:created", creationDate); // Nothing more } else { aDate = (Calendar) creationDate.clone(); aDate.add(Calendar.DATE, _randomInt(0, 30)); if (aDate.after(_today)) { aDate = (Calendar) _today.clone(); aDate.add(Calendar.DATE, _randomInt(0, 3) * -1); } oneGrandChild.setPropertyValue("dc:created", aDate); oneGrandChild.setProperty("dublincore", "creator", creator); oneGrandChild.setProperty("dublincore", "modified", creationDate); oneGrandChild.setProperty("dublincore", "lastContributor", kUSERS[_randomInt(0, kMAX_FOR_USERS_RANDOM)]); oneGrandChild.putContextData(DublinCoreListener.DISABLE_DUBLINCORE_LISTENER, true); } _session.saveDocument(oneGrandChild); } } } oneDoc.putContextData(DublinCoreListener.DISABLE_DUBLINCORE_LISTENER, true); // Make sure events are not triggered oneDoc.putContextData("UpdatingData_NoEventPlease", true); _saveDocument(oneDoc); } // for (DocumentModel oneDoc : allDocs) _doLog("Last commit. Total InsuranceClaim handled: " + _saveCounter); _session.save(); // ============================================================ // Create a nice case // ============================================================ _niceClaimCreate(); _session.save(); _doLog("End of update demo data"); } protected void updateLifecycleState(DocumentModel inDoc) { // ACTUALLY, NO. We consider that CreateDemoData has done the job already if (System.currentTimeMillis() != 0) { // Wich means "always" (want to keep the code below without comments or // having to go in git history) return; } String current = inDoc.getCurrentLifeCycleState(); // We keep 5% of "Received"? if (current.equals("Received") && _randomInt(1, 20) > 1) { inDoc.putContextData(DublinCoreListener.DISABLE_DUBLINCORE_LISTENER, true); inDoc.putContextData("UpdatingData_NoEventPlease", true); inDoc.followTransition("to_CheckContract"); int r = _randomInt(1, 100); // 57% of Archived +> we are at 62% if (r > 43) { inDoc.followTransition("to_Opened"); inDoc.followTransition("to_Completed"); inDoc.followTransition("to_Evaluated"); inDoc.followTransition("to_DecisionMade"); inDoc.followTransition("to_Archived"); } else if (r > 7) { // 7% stay in CheckContract => we are at 69% inDoc.followTransition("to_Opened"); if (r > 12) { inDoc.followTransition("to_Completed"); } if (r > 35) { inDoc.followTransition("to_Evaluated"); } // We ignore DesisionMade } } } /* * Centralize the way we find the nice claim */ protected DocumentModelList _niceClaimQuery() throws NuxeoException { String nxql; nxql = "SELECT * FROM InsuranceClaim"; nxql += " WHERE ecm:isCheckedInVersion = 0"; nxql += " AND ecm:currentLifeCycleState = 'DecisionMade'"; nxql += " AND " + kNICE_CLAIM_FIELD + " = '" + kNICE_CLAIM_FIELD_VALUE + "'"; return _session.query(nxql); } protected void _niceClaimDelete() throws NuxeoException { DocumentModelList allDocs = _niceClaimQuery(); int count = allDocs.size(); if (count != 0) { _doLog("Deleting previous Nice claim(s)..."); for (int i = 0; i < count; i++) { _session.removeDocument(allDocs.get(i).getRef()); } _session.save(); _doLog("...Nice claim(s) deleted"); } } /* * ============================================================ Create a nice case * ============================================================ Create a full, completed claim that will be used to * show the template rendering To identify the nice claim, we have a ugly trick: We store an information in the * kNICE_CLAIM_FIELD field. We delete an existing one if any, to rebuild it. We wait one second before each * modification when changing the lifecycle state so the audit log will be correctly sort. This means creating the * nice claim takes basically all the time ;-). */ protected void _niceClaimCreate() throws Exception { Calendar aDate, creationDate; String user, title; int count; DocumentModel niceClaim = null; _session.save(); _wait(1000); DocumentModelList allDocs = _niceClaimQuery(); count = allDocs.size(); if (count != 0) { _doLog("Deleting previous Nice claim(s)..."); for (int i = 0; i < count; i++) { _session.removeDocument(allDocs.get(i).getRef()); } _session.save(); _wait(2000); _doLog("...Nice claim(s) deleted"); } creationDate = _buildDate(_today, -20); // We first create the claim and let the Studio config on events // take the hand ("empty doc created" and "document created") // (setting some values, required by the chains ran by these handlers) // We also handle a unique path for this nice claim UIDSequencer svc = Framework.getService(UIDSequencer.class); title = _yyyyMMdd.format(creationDate.getTime()) + "-ACC-" + Integer.toString(svc.getNext("ACC")); niceClaim = _session.createDocumentModel(kNICE_CLAIM_PARENT_PATH, "claim-" + _yyyyMMdd.format(creationDate.getTime()) + "-" + Integer.toString(svc.getNext("NiceClaim")), "InsuranceClaim"); niceClaim.setPropertyValue("dc:title", title); niceClaim.setPropertyValue("incl:incident_id", title); niceClaim.setPropertyValue("incl:incident_kind", "accident"); niceClaim.setPropertyValue("incl:contract_id", "045-781-245"); niceClaim.setPropertyValue("incl:incident_date", creationDate); // Don't forget this one ;-> niceClaim.setPropertyValue(kNICE_CLAIM_FIELD, kNICE_CLAIM_FIELD_VALUE); niceClaim = _session.createDocument(niceClaim); _session.saveDocument(niceClaim); _session.save(); // Now update all infos niceClaim.setPropertyValue("dc:created", creationDate); niceClaim.setPropertyValue("incl:date_received", creationDate); user = kUSERS[_randomInt(0, kMAX_FOR_USERS_RANDOM)]; niceClaim.setPropertyValue("dc:creator", user); _updateModificationInfo(niceClaim, user, creationDate); _updateTitle(niceClaim, _yyyyMMdd.format(creationDate.getTime())); niceClaim.setPropertyValue("pein:first_name", "Alan"); niceClaim.setPropertyValue("pein:last_name", "Thecase"); niceClaim.setPropertyValue("pein:phone_main", "(123)-456-7890"); aDate = _buildDate(_today, _randomInt(30, 180) * -1); niceClaim.setPropertyValue("incl:contract_start", aDate); aDate.add(Calendar.DATE, 365); niceClaim.setPropertyValue("incl:contract_end", aDate); niceClaim.setPropertyValue("incl:due_date", _buildDate(_today, -2)); niceClaim.setPropertyValue("incl:incident_description", "I was driving the speed limit, and this car just came out of the parking lot and hit my car, on the front-left."); niceClaim.setPropertyValue("incl:incident_location", "1234 Nth 56 Street"); niceClaim.setPropertyValue("incl:incident_city", "New York"); niceClaim.setPropertyValue("incl:incident_weather", "Summary: Rain in the evening.\nWind Bearing: 88\nWindSpeed: 7.89\nHumidity: 0.81"); niceClaim.setPropertyValue("incl:repaid_amount", 260.0); niceClaim.setPropertyValue("incl:valuation_comments", ""); niceClaim.setPropertyValue("incl:valuation_estimates", 260.0); niceClaim.setPropertyValue("incl:valuation_on_site", false); niceClaim.putContextData("UpdatingData_NoEventPlease", true); _session.saveDocument(niceClaim); _session.save(); // And now, loop so we see the claim was modified 15-20 times // in the mean time, the lifecycle state is modified. We try // to make the audit lopk about ok... // NOTE: Well, this does not work very well: The audit uses the system // date of course, not dc:modified. // So, I keep this code, but for nice display of the audit, it is likely // that a the nxp_logs table of the db should be changed manually... // (or via a shell script started from here for example) String[] transitions = { "to_CheckContract", "to_Opened", "to_Completed", "to_Evaluated", "to_DecisionMade" }; int statsIdx = -1; aDate = (Calendar) creationDate.clone(); _doLog("Updating the Nice Claim"); // _doLog("Updating the Nice Claim, writing one second for each modif. Please, be patient (18-20 seconds)"); int maxModifLoop = 18; for (int i = 1; i < maxModifLoop; i++) { aDate = _buildDate(aDate, i); _updateModificationInfo(niceClaim, kUSERS[_randomInt(0, kMAX_FOR_USERS_RANDOM)], aDate); _session.saveDocument(niceClaim); _session.save(); // _wait(1000); _doLog(i + "/" + maxModifLoop); if ((i % 3) == 0) { statsIdx += 1; if (statsIdx < transitions.length) { _updateModificationInfo(niceClaim, kUSERS[_randomInt(0, kMAX_FOR_USERS_RANDOM)], aDate); niceClaim.putContextData(DublinCoreListener.DISABLE_DUBLINCORE_LISTENER, true); niceClaim.putContextData("UpdatingData_NoEventPlease", true); niceClaim.followTransition(transitions[statsIdx]); _session.saveDocument(niceClaim); _session.save(); // _wait(1000); _doLog(i + "/" + maxModifLoop + " (lifecycle: Following \"" + transitions[statsIdx] + "\")"); } } } _session.save(); _doLog("The \"nice claim\" is: " + niceClaim.getTitle()); _doLog("Path: " + niceClaim.getPathAsString() + "@view_documents"); } }