List of usage examples for android.content ContentValues get
public Object get(String key)
From source file:org.opendatakit.services.database.utilities.ODKDatabaseImplUtils.java
/** * Insert the given rowId with the values in the cvValues. If certain metadata * values are not specified in the cvValues, then suitable default values may * be supplied for them./*from w w w . java 2 s . c o m*/ * <p/> * If a row with this rowId and certain matching metadata fields is present, * then an exception is thrown. * * @param db * @param tableId * @param orderedColumns * @param cvValues * @param rowId * @param activeUser * @param rolesList * @param locale */ public void insertRowWithId(OdkConnectionInterface db, String tableId, OrderedColumns orderedColumns, ContentValues cvValues, String rowId, String activeUser, String rolesList, String locale) throws ActionNotAuthorizedException { if (cvValues == null) { throw new IllegalArgumentException(t + ": No values to add into table " + tableId); } HashMap<String, Object> cvDataTableVal = new HashMap<String, Object>(); cvDataTableVal.put(DataTableColumns.ID, rowId); for (String key : cvValues.keySet()) { cvDataTableVal.put(key, cvValues.get(key)); } upsertDataIntoExistingTable(db, tableId, orderedColumns, cvDataTableVal, false, false, activeUser, rolesList, locale, false); }
From source file:org.opendatakit.services.database.utilities.ODKDatabaseImplUtils.java
/** * Insert the given rowId with the values in the cvValues. All metadata field * values must be specified in the cvValues. This is called from Sync for inserting * a row verbatim from the server.//from w w w . j a v a2s . c o m * <p/> * If a row with this rowId is present, then an exception is thrown. * * @param db * @param tableId * @param orderedColumns * @param cvValues * @param rowId * @param activeUser * @param locale * @param asCsvRequestedChange */ public void privilegedInsertRowWithId(OdkConnectionInterface db, String tableId, OrderedColumns orderedColumns, ContentValues cvValues, String rowId, String activeUser, String locale, boolean asCsvRequestedChange) { String rolesList = RoleConsts.ADMIN_ROLES_LIST; if (cvValues == null || cvValues.size() <= 0) { throw new IllegalArgumentException(t + ": No values to add into table " + tableId); } HashMap<String, Object> cvDataTableVal = new HashMap<String, Object>(); cvDataTableVal.put(DataTableColumns.ID, rowId); for (String key : cvValues.keySet()) { cvDataTableVal.put(key, cvValues.get(key)); } // TODO: verify that all fields are specified try { upsertDataIntoExistingTable(db, tableId, orderedColumns, cvDataTableVal, false, true, activeUser, rolesList, locale, asCsvRequestedChange); } catch (ActionNotAuthorizedException e) { WebLogger.getLogger(db.getAppName()).printStackTrace(e); throw new IllegalStateException(e); } }
From source file:org.opendatakit.services.database.utilities.ODKDatabaseImplUtils.java
/** * Update the given rowId with the values in the cvValues. If certain metadata * values are not specified in the cvValues, then suitable default values may * be supplied for them. Furthermore, if the cvValues do not specify certain * metadata fields, then an exception may be thrown if there are more than one * row matching this rowId.//ww w . j a v a 2 s. c om * * @param db * @param tableId * @param orderedColumns * @param cvValues * @param rowId * @param activeUser * @param rolesList * @param locale */ public void updateRowWithId(OdkConnectionInterface db, String tableId, OrderedColumns orderedColumns, ContentValues cvValues, String rowId, String activeUser, String rolesList, String locale) throws ActionNotAuthorizedException { // TODO: make sure caller passes in the correct roleList for the use case. // TODO: for multi-step sync actions, we probably need an internal variant of this. if (cvValues.size() <= 0) { throw new IllegalArgumentException(t + ": No values to add into table " + tableId); } HashMap<String, Object> cvDataTableVal = new HashMap<String, Object>(); cvDataTableVal.put(DataTableColumns.ID, rowId); for (String key : cvValues.keySet()) { cvDataTableVal.put(key, cvValues.get(key)); } upsertDataIntoExistingTable(db, tableId, orderedColumns, cvDataTableVal, true, false, activeUser, rolesList, locale, false); }
From source file:org.opendatakit.services.database.utilities.ODKDatabaseImplUtils.java
/** * Update the given rowId with the values in the cvValues. All field * values are specified in the cvValues. This is a server-induced update * of the row to match all fields from the server. An error is thrown if * there isn't a row matching this rowId or if there are checkpoint or * conflict entries for this rowId./*from www . j a v a2 s .c o m*/ * * @param db * @param tableId * @param orderedColumns * @param cvValues * @param rowId * @param activeUser * @param locale * @param asCsvRequestedChange */ private void privilegedUpdateRowWithId(OdkConnectionInterface db, String tableId, OrderedColumns orderedColumns, ContentValues cvValues, String rowId, String activeUser, String locale, boolean asCsvRequestedChange) { // TODO: make sure caller passes in the correct roleList for the use case. // TODO: for multi-step sync actions, we probably need an internal variant of this. String rolesList = RoleConsts.ADMIN_ROLES_LIST; if (cvValues.size() <= 0) { throw new IllegalArgumentException(t + ": No values to add into table " + tableId); } HashMap<String, Object> cvDataTableVal = new HashMap<String, Object>(); cvDataTableVal.put(DataTableColumns.ID, rowId); for (String key : cvValues.keySet()) { cvDataTableVal.put(key, cvValues.get(key)); } try { upsertDataIntoExistingTable(db, tableId, orderedColumns, cvDataTableVal, true, true, activeUser, rolesList, locale, asCsvRequestedChange); } catch (ActionNotAuthorizedException e) { WebLogger.getLogger(db.getAppName()).printStackTrace(e); throw new IllegalStateException(e); } }
From source file:org.opendatakit.services.database.utlities.ODKDatabaseImplUtils.java
/** * Inserts a checkpoint row for the given rowId in the tableId. Checkpoint * rows are created by ODK Survey to hold intermediate values during the * filling-in of the form. They act as restore points in the Survey, should * the application die./* www . java 2s. c o m*/ * * @param db * @param tableId * @param orderedColumns * @param cvValues * @param rowId * @param activeUser * @param rolesList * @param locale */ public void insertCheckpointRowWithId(OdkConnectionInterface db, String tableId, OrderedColumns orderedColumns, ContentValues cvValues, String rowId, String activeUser, String rolesList, String locale) throws ActionNotAuthorizedException { if (cvValues.size() <= 0) { throw new IllegalArgumentException(t + ": No values to add into table for checkpoint" + tableId); } // these are all managed in the database layer... // the user should NOT set them... if (cvValues.containsKey(DataTableColumns.SAVEPOINT_TIMESTAMP)) { throw new IllegalArgumentException( t + ": No user supplied savepoint timestamp can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.SAVEPOINT_TYPE)) { throw new IllegalArgumentException( t + ": No user supplied savepoint type can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.ROW_ETAG)) { throw new IllegalArgumentException(t + ": No user supplied row ETag can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.SYNC_STATE)) { throw new IllegalArgumentException( t + ": No user supplied sync state can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.CONFLICT_TYPE)) { throw new IllegalArgumentException( t + ": No user supplied conflict type can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.FILTER_VALUE)) { throw new IllegalArgumentException( t + ": No user supplied filter value can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.FILTER_TYPE)) { throw new IllegalArgumentException( t + ": No user supplied filter type can be included for a checkpoint"); } // If a rowId is specified, a cursor will be needed to // get the current row to create a checkpoint with the relevant data Cursor c = null; try { // Allow the user to pass in no rowId if this is the first // checkpoint row that the user is adding if (rowId == null) { // TODO: is this even valid any more? I think we disallow this in the AIDL flow. String rowIdToUse = LocalizationUtils.genUUID(); HashMap<String, Object> currValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { currValues.put(key, cvValues.get(key)); } currValues.put(DataTableColumns._ID, rowIdToUse); currValues.put(DataTableColumns.SYNC_STATE, SyncState.new_row.name()); insertCheckpointIntoExistingTable(db, tableId, orderedColumns, currValues, activeUser, rolesList, locale, true, null, null); return; } StringBuilder b = new StringBuilder(); b.append(K_DATATABLE_ID_EQUALS_PARAM).append(S_AND).append(DataTableColumns.SAVEPOINT_TIMESTAMP) .append(" IN (SELECT MAX(").append(DataTableColumns.SAVEPOINT_TIMESTAMP).append(") FROM ") .append(tableId).append(K_WHERE).append(K_DATATABLE_ID_EQUALS_PARAM).append(")"); c = db.query(tableId, null, b.toString(), new Object[] { rowId, rowId }, null, null, null, null); c.moveToFirst(); if (c.getCount() > 1) { throw new IllegalStateException(t + ": More than one checkpoint at a timestamp"); } // Inserting a checkpoint for the first time if (c.getCount() <= 0) { HashMap<String, Object> currValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { currValues.put(key, cvValues.get(key)); } currValues.put(DataTableColumns._ID, rowId); currValues.put(DataTableColumns.SYNC_STATE, SyncState.new_row.name()); insertCheckpointIntoExistingTable(db, tableId, orderedColumns, currValues, activeUser, rolesList, locale, true, null, null); return; } else { // Make sure that the conflict_type of any existing row // is null, otherwise throw an exception int conflictIndex = c.getColumnIndex(DataTableColumns.CONFLICT_TYPE); if (!c.isNull(conflictIndex)) { throw new IllegalStateException( t + ": A checkpoint cannot be added for a row that is in conflict"); } HashMap<String, Object> currValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { currValues.put(key, cvValues.get(key)); } // This is unnecessary // We should only have one row at this point //c.moveToFirst(); String priorFilterType = null; String priorFilterValue = null; // Get the number of columns to iterate over and add // those values to the content values for (int i = 0; i < c.getColumnCount(); i++) { String name = c.getColumnName(i); if (currValues.containsKey(name)) { continue; } // omitting savepoint timestamp will generate a new timestamp. if (name.equals(DataTableColumns.SAVEPOINT_TIMESTAMP)) { continue; } // set savepoint type to null to mark this as a checkpoint if (name.equals(DataTableColumns.SAVEPOINT_TYPE)) { currValues.put(name, null); continue; } // sync state (a non-null field) should either remain 'new_row' // or be set to 'changed' for all other existing values. if (name.equals(DataTableColumns.SYNC_STATE)) { String priorState = c.getString(i); if (priorState.equals(SyncState.new_row.name())) { currValues.put(name, SyncState.new_row.name()); } else { currValues.put(name, SyncState.changed.name()); } continue; } if (c.isNull(i)) { currValues.put(name, null); continue; } // otherwise, just copy the values over... Class<?> theClass = CursorUtils.getIndexDataType(c, i); Object object = CursorUtils.getIndexAsType(c, theClass, i); insertValueIntoContentValues(currValues, theClass, name, object); if (name.equals(DataTableColumns.FILTER_TYPE)) { priorFilterType = c.getString(i); } if (name.equals(DataTableColumns.FILTER_VALUE)) { priorFilterValue = c.getString(i); } } insertCheckpointIntoExistingTable(db, tableId, orderedColumns, currValues, activeUser, rolesList, locale, false, priorFilterType, priorFilterValue); } } finally { if (c != null && !c.isClosed()) { c.close(); } } }
From source file:org.opendatakit.services.database.utilities.ODKDatabaseImplUtils.java
/** * Inserts a checkpoint row for the given rowId in the tableId. Checkpoint * rows are created by ODK Survey to hold intermediate values during the * filling-in of the form. They act as restore points in the Survey, should * the application die./*from w w w . ja v a 2 s.c om*/ * * @param db * @param tableId * @param orderedColumns * @param cvValues * @param rowId * @param activeUser * @param rolesList * @param locale */ public void insertCheckpointRowWithId(OdkConnectionInterface db, String tableId, OrderedColumns orderedColumns, ContentValues cvValues, String rowId, String activeUser, String rolesList, String locale) throws ActionNotAuthorizedException { if (cvValues.size() <= 0) { throw new IllegalArgumentException(t + ": No values to add into table for checkpoint" + tableId); } // these are all managed in the database layer... // the user should NOT set them... if (cvValues.containsKey(DataTableColumns.SAVEPOINT_TIMESTAMP)) { throw new IllegalArgumentException( t + ": No user supplied savepoint timestamp can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.SAVEPOINT_TYPE)) { throw new IllegalArgumentException( t + ": No user supplied savepoint type can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.ROW_ETAG)) { throw new IllegalArgumentException(t + ": No user supplied row ETag can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.SYNC_STATE)) { throw new IllegalArgumentException( t + ": No user supplied sync state can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.CONFLICT_TYPE)) { throw new IllegalArgumentException( t + ": No user supplied conflict type can be included for a checkpoint"); } // If a rowId is specified, a cursor will be needed to // get the current row to create a checkpoint with the relevant data Cursor c = null; try { // Allow the user to pass in no rowId if this is the first // checkpoint row that the user is adding if (rowId == null) { // TODO: is this even valid any more? I think we disallow this in the AIDL flow. String rowIdToUse = LocalizationUtils.genUUID(); HashMap<String, Object> currValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { currValues.put(key, cvValues.get(key)); } currValues.put(DataTableColumns._ID, rowIdToUse); currValues.put(DataTableColumns.SYNC_STATE, SyncState.new_row.name()); insertCheckpointIntoExistingTable(db, tableId, orderedColumns, currValues, activeUser, rolesList, locale, true, null, null, null, null, null); return; } StringBuilder b = new StringBuilder(); b.append(K_DATATABLE_ID_EQUALS_PARAM).append(S_AND).append(DataTableColumns.SAVEPOINT_TIMESTAMP) .append(" IN (SELECT MAX(").append(DataTableColumns.SAVEPOINT_TIMESTAMP).append(") FROM ") .append(tableId).append(K_WHERE).append(K_DATATABLE_ID_EQUALS_PARAM).append(")"); c = db.query(tableId, null, b.toString(), new Object[] { rowId, rowId }, null, null, null, null); c.moveToFirst(); if (c.getCount() > 1) { throw new IllegalStateException(t + ": More than one checkpoint at a timestamp"); } // Inserting a checkpoint for the first time if (c.getCount() <= 0) { HashMap<String, Object> currValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { currValues.put(key, cvValues.get(key)); } currValues.put(DataTableColumns._ID, rowId); currValues.put(DataTableColumns.SYNC_STATE, SyncState.new_row.name()); insertCheckpointIntoExistingTable(db, tableId, orderedColumns, currValues, activeUser, rolesList, locale, true, null, null, null, null, null); return; } else { // Make sure that the conflict_type of any existing row // is null, otherwise throw an exception int conflictIndex = c.getColumnIndex(DataTableColumns.CONFLICT_TYPE); if (!c.isNull(conflictIndex)) { throw new IllegalStateException( t + ": A checkpoint cannot be added for a row that is in conflict"); } // these are all managed in the database layer... // the user should NOT set them... if (cvValues.containsKey(DataTableColumns.DEFAULT_ACCESS)) { throw new IllegalArgumentException( t + ": No user supplied default access can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.ROW_OWNER)) { throw new IllegalArgumentException( t + ": No user supplied row owner can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.GROUP_READ_ONLY)) { throw new IllegalArgumentException( t + ": No user supplied group read only can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.GROUP_MODIFY)) { throw new IllegalArgumentException( t + ": No user supplied group modify can be included for a checkpoint"); } if (cvValues.containsKey(DataTableColumns.GROUP_PRIVILEGED)) { throw new IllegalArgumentException( t + ": No user supplied group privileged can be included for a checkpoint"); } HashMap<String, Object> currValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { currValues.put(key, cvValues.get(key)); } // This is unnecessary // We should only have one row at this point //c.moveToFirst(); String priorDefaultAccess = null; String priorOwner = null; String priorGroupReadOnly = null; String priorGroupModify = null; String priorGroupPrivileged = null; // Get the number of columns to iterate over and add // those values to the content values for (int i = 0; i < c.getColumnCount(); i++) { String name = c.getColumnName(i); if (name.equals(DataTableColumns.DEFAULT_ACCESS)) { priorDefaultAccess = c.getString(i); } if (name.equals(DataTableColumns.ROW_OWNER)) { priorOwner = c.getString(i); } if (name.equals(DataTableColumns.GROUP_READ_ONLY)) { priorGroupReadOnly = c.getString(i); } if (name.equals(DataTableColumns.GROUP_MODIFY)) { priorGroupModify = c.getString(i); } if (name.equals(DataTableColumns.GROUP_PRIVILEGED)) { priorGroupPrivileged = c.getString(i); } if (currValues.containsKey(name)) { continue; } // omitting savepoint timestamp will generate a new timestamp. if (name.equals(DataTableColumns.SAVEPOINT_TIMESTAMP)) { continue; } // set savepoint type to null to mark this as a checkpoint if (name.equals(DataTableColumns.SAVEPOINT_TYPE)) { currValues.put(name, null); continue; } // sync state (a non-null field) should either remain 'new_row' // or be set to 'changed' for all other existing values. if (name.equals(DataTableColumns.SYNC_STATE)) { String priorState = c.getString(i); if (priorState.equals(SyncState.new_row.name())) { currValues.put(name, SyncState.new_row.name()); } else { currValues.put(name, SyncState.changed.name()); } continue; } if (c.isNull(i)) { currValues.put(name, null); continue; } // otherwise, just copy the values over... Class<?> theClass = CursorUtils.getIndexDataType(c, i); Object object = CursorUtils.getIndexAsType(c, theClass, i); insertValueIntoContentValues(currValues, theClass, name, object); } insertCheckpointIntoExistingTable(db, tableId, orderedColumns, currValues, activeUser, rolesList, locale, false, priorDefaultAccess, priorOwner, priorGroupReadOnly, priorGroupModify, priorGroupPrivileged); } } finally { if (c != null && !c.isClosed()) { c.close(); } } }
From source file:org.opendatakit.services.database.utlities.ODKDatabaseImplUtils.java
/** * Resolve the server conflict by taking the local changes plus a value map * of select server field values. This map should not update any metadata * fields -- it should just contain user data fields. * <p/>/* w w w. j a va 2 s. c o m*/ * It is an error to call this if the local change is to delete the row. * * @param db * @param tableId * @param cvValues key-value pairs from the server record that we should incorporate. * @param rowId * @param activeUser * @param rolesList * @param locale */ public void resolveServerConflictTakeLocalRowPlusServerDeltasWithId(OdkConnectionInterface db, String tableId, ContentValues cvValues, String rowId, String activeUser, String rolesList, String locale) throws ActionNotAuthorizedException { // TODO: if rolesList does not contain RoleConsts.ROLE_SUPER_USER or RoleConsts.ROLE_ADMINISTRATOR // TODO: then take the server's rowFilterScope rather than the user's values of those. // TODO: and apply the update only if the user roles support that update. // I.e., if the user is super-user or higher, we should take local FilterScope. // otherwise, we should take server FilterScope. Or should we allow user to select // which to take? boolean inTransaction = false; try { inTransaction = db.inTransaction(); if (!inTransaction) { db.beginTransactionNonExclusive(); } OrderedColumns orderedColumns = getUserDefinedColumns(db, tableId); AccessContext accessContext = getAccessContext(db, tableId, activeUser, RoleConsts.ADMIN_ROLES_LIST); // get both conflict records for this row. // the local record is always before the server record (due to conflict_type values) BaseTable table = privilegedQuery(db, tableId, QueryUtil.buildSqlStatement(tableId, K_DATATABLE_ID_EQUALS_PARAM + S_AND + DataTableColumns.CONFLICT_TYPE + S_IS_NOT_NULL, null, null, new String[] { DataTableColumns.CONFLICT_TYPE }, new String[] { "ASC" }), new Object[] { rowId }, null, accessContext); if (table.getNumberOfRows() != 2) { throw new IllegalStateException( "Did not find a server and local row when resolving conflicts for rowId: " + rowId); } Row localRow = table.getRowAtIndex(0); Row serverRow = table.getRowAtIndex(1); int localConflictType = Integer.parseInt(localRow.getDataByKey(DataTableColumns.CONFLICT_TYPE)); int serverConflictType = Integer.parseInt(serverRow.getDataByKey(DataTableColumns.CONFLICT_TYPE)); if (localConflictType != ConflictType.LOCAL_UPDATED_UPDATED_VALUES && localConflictType != ConflictType.LOCAL_DELETED_OLD_VALUES) { throw new IllegalStateException( "Did not find local conflict row when resolving conflicts for rowId: " + rowId); } if (serverConflictType != ConflictType.SERVER_UPDATED_UPDATED_VALUES && serverConflictType != ConflictType.SERVER_DELETED_OLD_VALUES) { throw new IllegalStateException( "Did not find server conflict row when resolving conflicts for rowId: " + rowId); } if (localConflictType == ConflictType.LOCAL_DELETED_OLD_VALUES) { throw new IllegalStateException( "Local row is marked for deletion -- blending does not make sense for rowId: " + rowId); } HashMap<String, Object> updateValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { updateValues.put(key, cvValues.get(key)); } // clean up the incoming map of server values to retain cleanUpValuesMap(orderedColumns, updateValues); updateValues.put(DataTableColumns.ID, rowId); updateValues.put(DataTableColumns.ROW_ETAG, serverRow.getDataByKey(DataTableColumns.ROW_ETAG)); // update what was the local conflict record with the local's changes // by the time we apply the update, the local conflict record will be // restored to the proper (conflict_type, sync_state) values. // // No need to specify them here. // but take the local's metadata values (i.e., do not change these // during the update) ... updateValues.put(DataTableColumns.FORM_ID, localRow.getDataByKey(DataTableColumns.FORM_ID)); updateValues.put(DataTableColumns.LOCALE, localRow.getDataByKey(DataTableColumns.LOCALE)); updateValues.put(DataTableColumns.SAVEPOINT_TYPE, localRow.getDataByKey(DataTableColumns.SAVEPOINT_TYPE)); updateValues.put(DataTableColumns.SAVEPOINT_TIMESTAMP, localRow.getDataByKey(DataTableColumns.SAVEPOINT_TIMESTAMP)); updateValues.put(DataTableColumns.SAVEPOINT_CREATOR, localRow.getDataByKey(DataTableColumns.SAVEPOINT_CREATOR)); // take the server's filter metadata values ... TreeMap<String, Object> privilegedUpdateValues = new TreeMap<String, Object>(); privilegedUpdateValues.put(DataTableColumns.ID, rowId); privilegedUpdateValues.put(DataTableColumns.FILTER_TYPE, serverRow.getDataByKey(DataTableColumns.FILTER_TYPE)); privilegedUpdateValues.put(DataTableColumns.FILTER_VALUE, serverRow.getDataByKey(DataTableColumns.FILTER_VALUE)); privilegedUpdateValues.put(DataTableColumns.SAVEPOINT_TIMESTAMP, serverRow.getDataByKey(DataTableColumns.SAVEPOINT_TIMESTAMP)); privilegedUpdateValues.put(DataTableColumns.SAVEPOINT_CREATOR, serverRow.getDataByKey(DataTableColumns.SAVEPOINT_CREATOR)); // delete the record of the server row deleteServerConflictRowWithId(db, tableId, rowId); // move the local conflict back into the normal (null) state restoreRowFromConflict(db, tableId, rowId, SyncState.changed, localConflictType); // update local with server's changes updateRowWithId(db, tableId, orderedColumns, updateValues, activeUser, rolesList, locale); // update as if user has admin privileges. // do this so we can update the filter type and filter value updateRowWithId(db, tableId, orderedColumns, privilegedUpdateValues, activeUser, RoleConsts.ADMIN_ROLES_LIST, locale); if (!inTransaction) { db.setTransactionSuccessful(); } } finally { if (db != null) { if (!inTransaction) { db.endTransaction(); } } } }
From source file:org.opendatakit.services.database.utilities.ODKDatabaseImplUtils.java
/** * Resolve the server conflict by taking the local changes plus a value map * of select server field values. This map should not update any metadata * fields -- it should just contain user data fields. * <p/>//w w w. ja v a 2 s . c om * It is an error to call this if the local change is to delete the row. * * @param db * @param tableId * @param cvValues key-value pairs from the server record that we should incorporate. * @param rowId * @param activeUser * @param rolesList * @param locale */ public void resolveServerConflictTakeLocalRowPlusServerDeltasWithId(OdkConnectionInterface db, String tableId, ContentValues cvValues, String rowId, String activeUser, String rolesList, String locale) throws ActionNotAuthorizedException { // TODO: if rolesList does not contain RoleConsts.ROLE_SUPER_USER or RoleConsts.ROLE_ADMINISTRATOR // TODO: then take the server's rowFilterScope rather than the user's values of those. // TODO: and apply the update only if the user roles support that update. // I.e., if the user is super-user or higher, we should take local FilterScope. // otherwise, we should take server FilterScope. Or should we allow user to select // which to take? boolean inTransaction = false; try { inTransaction = db.inTransaction(); if (!inTransaction) { db.beginTransactionNonExclusive(); } OrderedColumns orderedColumns = getUserDefinedColumns(db, tableId); AccessContext accessContext = getAccessContext(db, tableId, activeUser, RoleConsts.ADMIN_ROLES_LIST); // get both conflict records for this row. // the local record is always before the server record (due to conflict_type values) BaseTable table = privilegedQuery(db, tableId, QueryUtil.buildSqlStatement(tableId, K_DATATABLE_ID_EQUALS_PARAM + S_AND + DataTableColumns.CONFLICT_TYPE + S_IS_NOT_NULL, null, null, new String[] { DataTableColumns.CONFLICT_TYPE }, new String[] { "ASC" }), new Object[] { rowId }, null, accessContext); if (table.getNumberOfRows() != 2) { throw new IllegalStateException( "Did not find a server and local row when resolving conflicts for rowId: " + rowId); } Row localRow = table.getRowAtIndex(0); Row serverRow = table.getRowAtIndex(1); int localConflictType = Integer.parseInt(localRow.getDataByKey(DataTableColumns.CONFLICT_TYPE)); int serverConflictType = Integer.parseInt(serverRow.getDataByKey(DataTableColumns.CONFLICT_TYPE)); if (localConflictType != ConflictType.LOCAL_UPDATED_UPDATED_VALUES && localConflictType != ConflictType.LOCAL_DELETED_OLD_VALUES) { throw new IllegalStateException( "Did not find local conflict row when resolving conflicts for rowId: " + rowId); } if (serverConflictType != ConflictType.SERVER_UPDATED_UPDATED_VALUES && serverConflictType != ConflictType.SERVER_DELETED_OLD_VALUES) { throw new IllegalStateException( "Did not find server conflict row when resolving conflicts for rowId: " + rowId); } if (localConflictType == ConflictType.LOCAL_DELETED_OLD_VALUES) { throw new IllegalStateException( "Local row is marked for deletion -- blending does not make sense for rowId: " + rowId); } HashMap<String, Object> updateValues = new HashMap<String, Object>(); for (String key : cvValues.keySet()) { updateValues.put(key, cvValues.get(key)); } // clean up the incoming map of server values to retain cleanUpValuesMap(orderedColumns, updateValues); updateValues.put(DataTableColumns.ID, rowId); updateValues.put(DataTableColumns.ROW_ETAG, serverRow.getDataByKey(DataTableColumns.ROW_ETAG)); // update what was the local conflict record with the local's changes // by the time we apply the update, the local conflict record will be // restored to the proper (conflict_type, sync_state) values. // // No need to specify them here. // but take the local's metadata values (i.e., do not change these // during the update) ... updateValues.put(DataTableColumns.FORM_ID, localRow.getDataByKey(DataTableColumns.FORM_ID)); updateValues.put(DataTableColumns.LOCALE, localRow.getDataByKey(DataTableColumns.LOCALE)); updateValues.put(DataTableColumns.SAVEPOINT_TYPE, localRow.getDataByKey(DataTableColumns.SAVEPOINT_TYPE)); updateValues.put(DataTableColumns.SAVEPOINT_TIMESTAMP, localRow.getDataByKey(DataTableColumns.SAVEPOINT_TIMESTAMP)); updateValues.put(DataTableColumns.SAVEPOINT_CREATOR, localRow.getDataByKey(DataTableColumns.SAVEPOINT_CREATOR)); // take the server's filter metadata values ... TreeMap<String, Object> privilegedUpdateValues = new TreeMap<String, Object>(); privilegedUpdateValues.put(DataTableColumns.ID, rowId); privilegedUpdateValues.put(DataTableColumns.DEFAULT_ACCESS, serverRow.getDataByKey(DataTableColumns.DEFAULT_ACCESS)); privilegedUpdateValues.put(DataTableColumns.ROW_OWNER, serverRow.getDataByKey(DataTableColumns.ROW_OWNER)); privilegedUpdateValues.put(DataTableColumns.GROUP_READ_ONLY, serverRow.getDataByKey(DataTableColumns.GROUP_READ_ONLY)); privilegedUpdateValues.put(DataTableColumns.GROUP_MODIFY, serverRow.getDataByKey(DataTableColumns.GROUP_MODIFY)); privilegedUpdateValues.put(DataTableColumns.GROUP_PRIVILEGED, serverRow.getDataByKey(DataTableColumns.GROUP_PRIVILEGED)); privilegedUpdateValues.put(DataTableColumns.SAVEPOINT_TIMESTAMP, serverRow.getDataByKey(DataTableColumns.SAVEPOINT_TIMESTAMP)); privilegedUpdateValues.put(DataTableColumns.SAVEPOINT_CREATOR, serverRow.getDataByKey(DataTableColumns.SAVEPOINT_CREATOR)); // delete the record of the server row deleteServerConflictRowWithId(db, tableId, rowId); // move the local conflict back into the normal (null) state restoreRowFromConflict(db, tableId, rowId, SyncState.changed, localConflictType); // update local with server's changes updateRowWithId(db, tableId, orderedColumns, updateValues, activeUser, rolesList, locale); // update as if user has admin privileges. // do this so we can update the filter type and filter value updateRowWithId(db, tableId, orderedColumns, privilegedUpdateValues, activeUser, RoleConsts.ADMIN_ROLES_LIST, locale); if (!inTransaction) { db.setTransactionSuccessful(); } } finally { if (db != null) { if (!inTransaction) { db.endTransaction(); } } } }