Java tutorial
/* * Odoo, Open Source Management Solution * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version * * This program 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 Affero General Public License for more details * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http:www.gnu.org/licenses/> * */ package com.odoo.orm; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import odoo.ODomain; import odoo.OdooVersion; import org.json.JSONObject; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.os.AsyncTask; import android.util.Log; import com.odoo.App; import com.odoo.orm.OColumn.RelationType; import com.odoo.orm.ORelIds.RelData; import com.odoo.orm.annotations.Odoo; import com.odoo.orm.annotations.Odoo.Functional; import com.odoo.orm.sql.OQuery; import com.odoo.orm.sql.OQuery.QueryType; import com.odoo.orm.types.OBoolean; import com.odoo.orm.types.ODateTime; import com.odoo.orm.types.OInteger; import com.odoo.orm.types.OText; import com.odoo.orm.types.OVarchar; import com.odoo.receivers.DataSetChangeReceiver; import com.odoo.support.OUser; import com.odoo.support.provider.OContentProvider; import com.odoo.support.provider.OContentProviderHelper; import com.odoo.util.ODate; import com.odoo.util.PreferenceManager; import com.odoo.util.StringUtils; import com.odoo.util.logger.OLog; /** * The Class OModel. */ public class OModel extends OSQLiteHelper implements OModelHelper { /** The Constant TAG. */ public static final String TAG = OModel.class.getSimpleName(); /** The context. */ private Context mContext = null; /** The _name. */ private String _name = null; /** The columns. */ private List<OColumn> mColumns = new ArrayList<OColumn>(); /** The functional columns. */ private List<OColumn> mFunctionalColumns = new ArrayList<OColumn>(); private List<OColumn> mRelationColumns = new ArrayList<OColumn>(); /** The user. */ private OUser mUser = null; /** The sync helper. */ private OSyncHelper mSyncHelper = null; /** The syncing data. */ private Boolean mSyncingData = false; /** The check in active record. */ private Boolean mCheckInActiveRecord = false; /** The app. */ private App mApp = null; /** The odoo version. */ private OdooVersion mOdooVersion = null; /** The offset. */ private Integer mOffset = 0; /** The limit. */ private Integer mLimit = -1; /** The with functional columns. */ private Boolean mWithFunctionalColumns = false; /** * The Enum Command. */ public enum Command { /** The Add. */ Add, /** The Update. */ Update, /** The Delete. */ Delete, /** The Replace. */ Replace } // Server Base Columns /** The id. */ OColumn id = new OColumn("ID", OInteger.class).setDefault(0); /** The create_date. */ @Odoo.api.v8 @Odoo.api.v9alpha public OColumn create_date = new OColumn("Created On", ODateTime.class).setParsePattern(ODate.DEFAULT_FORMAT); /** The write_date. */ @Odoo.api.v8 @Odoo.api.v9alpha public OColumn write_date = new OColumn("Last Updated On", ODateTime.class) .setParsePattern(ODate.DEFAULT_FORMAT); // Local Base Columns /** The _id. */ OColumn _id = new OColumn("Local ID", OInteger.class).setAutoIncrement(true).setLocalColumn(); /** The odoo_name. */ OColumn odoo_name = new OColumn("Odoo Account Name", OVarchar.class, 100).setRequired(true).setLocalColumn(); /** The local_write_date. */ OColumn local_write_date = new OColumn("Local Write Date", ODateTime.class).setLocalColumn(); /** The is_dirty. */ OColumn is_dirty = new OColumn("Dirty Row", OText.class).setDefault(false).setLocalColumn(); /** The is_active. */ OColumn is_active = new OColumn("Row Active", OBoolean.class).setDefault(true).setLocalColumn(); /** The declared fields. */ private HashMap<String, Field> mDeclaredFields = new HashMap<String, Field>(); public static String getSyncUserDB(Context context) { OUser user = OModel.getSyncUser(context); if (user != null) { return user.getDBName(); } return ""; } public static OUser getSyncUser(Context context) { App app = (App) context.getApplicationContext(); OUser user = app.getSyncUser(); if (user == null) { user = OUser.current(context); } return user; } /** * Instantiates a new o model. * * @param context * the context * @param model_name * the model_name */ public OModel(Context context, String model_name) { super(context, OModel.getSyncUserDB(context)); mContext = context; _name = model_name; mUser = OUser.current(mContext); mApp = (App) context.getApplicationContext(); if (mUser != null) { mOdooVersion = new OdooVersion(); mOdooVersion.setVersion_number(mUser.getVersion_number()); mOdooVersion.setServer_serie(mUser.getVersion_serie()); } else { mApp.createInstance(); mOdooVersion = mApp.getOdooVersion(); } createFieldList(); } public OModel newInstance(OModel model) { try { return model.getClass().newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } public OContentProvider getContentProvider() { return null; } /** * Generate content Uri. * * @return the uri */ public Uri uri() { return OContentProvider.buildURI(authority(), path()); } public String path() { OContentProviderHelper provider = (OContentProviderHelper) getContentProvider(); if (provider != null) return provider.path(); else OLog.log("Override getContentProvider() method in " + getClass().getSimpleName()); return null; } /** * Generate content Authority. * * @return the string */ public String authority() { OContentProviderHelper provider = (OContentProviderHelper) getContentProvider(); if (provider != null) return provider.authority(); else OLog.log("Override getContentProvider() method in " + getClass().getSimpleName()); return null; } /** * Sets the user. * * @param user * the new user */ public void setUser(OUser user) { mUser = user; } public OUser getUser() { return mUser; } /** * Gets the model name. * * @return the model name */ public String getModelName() { return _name; } /** * Gets the table name. * * @return the table name */ public String getTableName() { return _name.replaceAll("\\.", "_"); } /* * (non-Javadoc) * * @see com.odoo.orm.OModelHelper#getColumns() */ public List<OColumn> getColumns() { return getColumns(null); } /* * (non-Javadoc) * * @see com.odoo.orm.OModelHelper#getColumns(java.lang.Boolean) */ @Override public List<OColumn> getColumns(Boolean local) { if (mColumns.size() <= 0) { prepareColumns(); } if (local != null) { List<OColumn> cols = new ArrayList<OColumn>(); for (OColumn column : getColumns()) if (local == column.isLocal()) cols.add(column); return cols; } else { return mColumns; } } /* * (non-Javadoc) * * @see com.odoo.orm.OModelHelper#defaultDomain() */ @Override public ODomain defaultDomain() { return new ODomain(); } /** * Gets the many to many columns. * * @param relation_model * the relation_model * @return the many to many columns */ public List<OColumn> getManyToManyColumns(OModel relation_model) { List<OColumn> cols = new ArrayList<OColumn>(); odoo_name.setName("odoo_name"); cols.add(odoo_name); local_write_date.setName("local_write_date"); cols.add(local_write_date); is_dirty.setName("is_dirty"); cols.add(is_dirty); is_active.setName("is_active"); cols.add(is_active); OColumn base_id = new OColumn("Base Id", OInteger.class); base_id.setName(getTableName() + "_id"); cols.add(base_id); OColumn relation_id = new OColumn("Relation Id", OInteger.class); relation_id.setName(relation_model.getTableName() + "_id"); cols.add(relation_id); return cols; } private void createFieldList() { try { List<Field> fields = new ArrayList<Field>(); fields.addAll(Arrays.asList(getClass().getSuperclass().getDeclaredFields())); fields.addAll(Arrays.asList(getClass().getDeclaredFields())); mDeclaredFields.clear(); for (Field field : fields) { if (field.getType().isAssignableFrom(OColumn.class)) { mDeclaredFields.put(field.getName(), field); } } } catch (Exception e) { e.printStackTrace(); } } /** * Prepare columns. */ public void prepareColumns() { if (mDeclaredFields.size() == 0) createFieldList(); for (String key : mDeclaredFields.keySet()) { OColumn column = getColumn(key); if (column != null) { if (column.getRelationType() != null) { mRelationColumns.add(column); } if (column.isFunctionalColumn()) { if (column.canFunctionalStore()) { mColumns.add(column); } mFunctionalColumns.add(column); } else { mColumns.add(column); } } } } public List<OColumn> getRelationColumns() { return mRelationColumns; } public List<OColumn> getFunctionalColumns() { return mFunctionalColumns; } /** * Gets the column. * * @param name * the name * @return the column */ public OColumn getColumn(String name) { OColumn column = null; try { Field field = mDeclaredFields.get(name); if (field != null) { field.setAccessible(true); column = (OColumn) field.get(this); column.setName(field.getName()); Boolean validField = (column.isAccessible()) ? validateFieldVersion(field) : true; if (validField) { Method method = checkForFunctionalColumn(field); column.setName(name); if (method != null) { column.setFunctionalMethod(method); column.setFunctionalStore(checkForFunctionalStore(field)); column.checkRowId(checkForFunctionalRowIdCheck(field)); if (column.canFunctionalStore()) { column.setFunctionalStoreDepends(getFunctionalDepends(field)); } else { column.setLocalColumn(); } } // Check for onChange Column Method onChangeMethod = checkForOnChangeMethod(field); if (onChangeMethod != null) { column.setOnChangeMethod(onChangeMethod); column.setOnChangeBGProcess(checkForOnChangeBGProcess(field)); } // Check for domain Filter on Column column.setHasDomainFilterColumn(isDomainFilterColumn(field)); } else return null; } } catch (Exception e) { e.printStackTrace(); } return column; } public OColumn getPermReadColumn(String name) { OColumn column = null; try { Field field = getClass().getSuperclass().getDeclaredField(name); if (field != null) { field.setAccessible(true); if (validateFieldVersion(field)) { Method method = checkForFunctionalColumn(field); column = (OColumn) field.get(this); column.setName(name); if (method != null) { column.setFunctionalMethod(method); column.setFunctionalStore(checkForFunctionalStore(field)); if (column.canFunctionalStore()) { column.setFunctionalStoreDepends(getFunctionalDepends(field)); } } } } } catch (Exception e) { e.printStackTrace(); } return column; } /** * Check for functional column. * * @param field * the field * @return the method */ private Method checkForFunctionalColumn(Field field) { Annotation annotation = field.getAnnotation(Odoo.Functional.class); if (annotation != null) { Odoo.Functional functional = (Functional) annotation; String method_name = functional.method(); try { if (functional.store()) return getClass().getMethod(method_name, OValues.class); else return getClass().getMethod(method_name, ODataRow.class); } catch (NoSuchMethodException e) { Log.e(TAG, "No Such Method: " + e.getMessage()); } } return null; } private boolean isDomainFilterColumn(Field field) { Annotation annotation = field.getAnnotation(Odoo.hasDomainFilter.class); if (annotation != null) { Odoo.hasDomainFilter domainFilter = (Odoo.hasDomainFilter) annotation; return domainFilter.checkDomainRuntime(); } return false; } private Boolean checkForOnChangeBGProcess(Field field) { Annotation annotation = field.getAnnotation(Odoo.onChange.class); if (annotation != null) { Odoo.onChange onChange = (Odoo.onChange) annotation; return onChange.bg_process(); } return false; } private Method checkForOnChangeMethod(Field field) { Annotation annotation = field.getAnnotation(Odoo.onChange.class); if (annotation != null) { Odoo.onChange onChange = (Odoo.onChange) annotation; String method_name = onChange.method(); try { return getClass().getMethod(method_name, ODataRow.class); } catch (NoSuchMethodException e) { Log.e(TAG, "No Such Method: " + e.getMessage()); } } return null; } /** * Check for functional store. * * @param field * the field * @return the boolean */ public Boolean checkForFunctionalStore(Field field) { Annotation annotation = field.getAnnotation(Odoo.Functional.class); if (annotation != null) { Odoo.Functional functional = (Functional) annotation; return functional.store(); } return false; } /** * Check for functional row id check. * * @param field * the field * @return the boolean */ private Boolean checkForFunctionalRowIdCheck(Field field) { Annotation annotation = field.getAnnotation(Odoo.Functional.class); if (annotation != null) { Odoo.Functional functional = (Functional) annotation; return functional.checkRowId(); } return true; } /** * Gets the functional depends. * * @param field * the field * @return the functional depends */ public String[] getFunctionalDepends(Field field) { Annotation annotation = field.getAnnotation(Odoo.Functional.class); if (annotation != null) { Odoo.Functional functional = (Functional) annotation; if (functional.store()) { return functional.depends(); } } return null; } public OdooVersion getOdooVersion() { return mOdooVersion; } private Boolean validateFieldVersion(Field field) { if (mOdooVersion != null) { Annotation[] annotations = field.getAnnotations(); if (annotations.length > 0) { int versions = 0; for (Annotation annotation : annotations) { if (annotation.annotationType().getDeclaringClass().isAssignableFrom(Odoo.api.class)) { switch (mOdooVersion.getVersion_number()) { case 9: // Checks for v9 if (annotation.annotationType().isAssignableFrom(Odoo.api.v9alpha.class)) { versions++; } break; case 8: // Checks for v8 if (annotation.annotationType().isAssignableFrom(Odoo.api.v8.class)) { versions++; } break; case 7: // Checks for v7 if (annotation.annotationType().isAssignableFrom(Odoo.api.v7.class)) { versions++; } break; } } Class<? extends Annotation> type = annotation.annotationType(); if (type.isAssignableFrom(Odoo.Functional.class) || type.isAssignableFrom(Odoo.onChange.class) || type.isAssignableFrom(Odoo.hasDomainFilter.class)) { versions++; } } return (versions > 0) ? true : false; } return true; } return false; } /** * Gets the functional method value. * * @param column * the column * @param record * the record * @return the functional method value */ public Object getFunctionalMethodValue(OColumn column, Object record) { if (column.isFunctionalColumn()) { Method method = column.getMethod(); OModel model = this; try { return method.invoke(model, new Object[] { record }); } catch (Exception e) { e.printStackTrace(); } } return false; } public ODataRow getOnChangeValue(OColumn column, ODataRow row) { if (column.hasOnChange()) { Method method = column.getOnChangeMethod(); OModel model = this; try { return (ODataRow) method.invoke(model, new Object[] { row }); } catch (Exception e) { e.printStackTrace(); } } return null; } /** * Creates the instance. * * @param model_class * the model_class * @return the o model */ public OModel createInstance(Class<?> model_class) { try { Constructor<?> constr = model_class.getConstructor(Context.class); OModel model = (OModel) constr.newInstance(new Object[] { mContext }); return model; } catch (Exception e) { Log.d(TAG, model_class.getSimpleName()); e.printStackTrace(); } return null; } /** * Generate columns string array used as Projection in ContentProvider. * * @return the string[] */ public String[] projection() { List<String> projection = new ArrayList<String>(); for (OColumn col : getColumns()) { if (col.getRelationType() == null || (col.getRelationType() != null && col.getRelationType() == RelationType.ManyToOne)) { projection.add(col.getName()); } } return projection.toArray(new String[projection.size()]); } public String[] fields() { List<String> fields = new ArrayList<String>(); for (OColumn col : getColumns(false)) { fields.add(col.getName()); } return fields.toArray(new String[fields.size()]); } /** * Select. * * @return the list */ public List<ODataRow> select() { return select(null, null, null, null, null); } /** * Select. * * @param id * the id * @return the o data row */ public ODataRow select(Integer id) { String selection = OColumn.ROW_ID + " = ?"; List<ODataRow> records = select(selection, new Object[] { id }, null, null, null); if (records.size() > 0) return records.get(0); return null; } public Integer selectRowId(Integer server_id) { List<ODataRow> records = select("id = ? ", new Object[] { server_id }); if (records.size() > 0) { return records.get(0).getInt(OColumn.ROW_ID); } return null; } public Integer selectServerId(Integer row_id) { List<ODataRow> records = browse().columns("id", OColumn.ROW_ID, "name") .addWhere(OColumn.ROW_ID, "=", row_id).fetch(); if (records.size() > 0) { return records.get(0).getInt("id"); } return null; } /** * Select. * * @param where * the where * @param args * the args * @return the list */ public List<ODataRow> select(String where, Object[] args) { return select(where, args, null, null, null); } /** * Select. * * @param where * the where * @param whereArgs * the where args * @param groupBy * the group by * @param having * the having * @param orderBy * the order by * @return the list */ public List<ODataRow> select(String where, Object[] whereArgs, String groupBy, String having, String orderBy) { List<ODataRow> records = new ArrayList<ODataRow>(); SQLiteDatabase db = getReadableDatabase(); String limit = null; if (mLimit > 0) { limit = mOffset + ", " + mLimit; } Cursor cr = db.query(getTableName(), new String[] { "*" }, getWhereClause(where), getWhereArgs(where, whereArgs), groupBy, having, orderBy, limit); if (cr.moveToFirst()) { do { ODataRow row = new ODataRow(); for (OColumn col : getColumns()) { if (col.getRelationType() == null) { row.put(col.getName(), createRecordRow(col, cr)); } else { switch (col.getRelationType()) { case ManyToMany: row.put(col.getName(), new OM2MRecord(this, col, cr.getInt(cr.getColumnIndex(OColumn.ROW_ID)))); break; case OneToMany: row.put(col.getName(), new OO2MRecord(this, col, cr.getInt(cr.getColumnIndex(OColumn.ROW_ID)))); break; case ManyToOne: row.put(col.getName(), new OM2ORecord(this, col, cr.getInt(cr.getColumnIndex(col.getName())))); break; } } } /* * Adding functional column values to record values if not * syncing */ if (!mSyncingData) { for (OColumn col : mFunctionalColumns) { if (!col.canFunctionalStore()) { row.put(col.getName(), getFunctionalMethodValue(col, row)); } } } if (row.getInt("id") == 0 || row.getString("id").equals("false")) row.put("id", 0); records.add(row); } while (cr.moveToNext()); } cr.close(); db.close(); return records; } public List<ODataRow> query(String sql, String[] args) { return query(sql, args, true); } public List<ODataRow> query(String sql, String[] args, Boolean closeConnection) { List<ODataRow> records = new ArrayList<ODataRow>(); SQLiteDatabase db = getReadableDatabase(); Cursor cr = db.rawQuery(sql, args); if (cr.moveToFirst()) { do { ODataRow row = createRowFromCursor(cr); if (mWithFunctionalColumns) { for (OColumn col : mFunctionalColumns) { if (!col.canFunctionalStore()) { row.put(col.getName(), getFunctionalMethodValue(col, row)); } } } records.add(row); } while (cr.moveToNext()); } cr.close(); if (closeConnection) db.close(); return records; } public ODataRow selectRelRecord(String[] columns, int base_id) { ODataRow row = new ODataRow(); for (String col : columns) { OColumn column = getColumn(col); if (column.getRelationType() != null) { switch (column.getRelationType()) { case ManyToMany: row.put(column.getName(), new OM2MRecord(this, column, base_id)); break; case OneToMany: row.put(column.getName(), new OO2MRecord(this, column, base_id)); break; case ManyToOne: row.put(column.getName(), new OM2ORecord(this, column, base_id)); break; } } } return row; } public OModel withFunctionalColumns() { return withFunctionalColumns(true); } public OModel withFunctionalColumns(Boolean withFunctionalColumns) { mWithFunctionalColumns = withFunctionalColumns; if (withFunctionalColumns) { prepareColumns(); } return this; } public ODataRow createRowFromCursor(Cursor cr) { ODataRow row = new ODataRow(); for (String col_name : cr.getColumnNames()) { OColumn col = new OColumn(col_name).setDefault(false); col.setName(col_name); row.put(col_name, createRecordRow(col, cr)); } if (row.getInt("id") == 0 || row.getString("id").equals("false")) row.put("id", 0); return row; } /** * Gets the name. * * @param model * the model * @param row_id * the row_id * @return the name */ public String getName(int row_id) { String name = "false"; if (getColumn("name") != null) { SQLiteDatabase db = getReadableDatabase(); Cursor cr = db.query(getTableName(), new String[] { "name" }, OColumn.ROW_ID + " = ?", new String[] { row_id + "" }, null, null, null); if (cr.moveToFirst()) { name = cr.getString(cr.getColumnIndex("name")); } cr.close(); db.close(); } return name; } /** * Select one to many rel ids. * * @param base * the base * @param rel * the rel * @param base_id * the base_id * @param ref_column * the ref_column * @return the list */ public List<Integer> selecto2MRelIds(OModel base, OModel rel, int base_id, String ref_column) { List<Integer> ids = new ArrayList<Integer>(); SQLiteDatabase db = getReadableDatabase(); Cursor cr = db.query(rel.getTableName(), new String[] { "id" }, ref_column + " = ?", new String[] { base_id + "" }, null, null, null); if (cr.moveToFirst()) { do { ids.add(cr.getInt(cr.getColumnIndex("id"))); } while (cr.moveToNext()); } cr.close(); db.close(); return ids; } /** * Select many to many rel ids. * * @param base * the base * @param rel * the rel * @param base_id * the base_id * @return the list */ public List<Integer> selectM2MRelIds(OModel base, OModel rel, int base_id) { List<Integer> ids = new ArrayList<Integer>(); String table = base.getTableName() + "_" + rel.getTableName() + "_rel"; String base_col = base.getTableName() + "_id"; String rel_col = rel.getTableName() + "_id"; SQLiteDatabase db = getReadableDatabase(); String where = base_col + " = ? and odoo_name = ?"; Object[] whereArgs = new Object[] { base_id, mUser.getAndroidName() }; Cursor cr = db.query(table, new String[] { "*" }, getWhereClause(where), getWhereArgs(where, whereArgs), null, null, null); if (cr.moveToFirst()) { do { int rel_id = cr.getInt(cr.getColumnIndex(rel_col)); if (rel.count(OColumn.ROW_ID + " = ?", new Object[] { rel_id }) > 0) ids.add(rel_id); } while (cr.moveToNext()); } cr.close(); db.close(); return ids; } /** * Select m2 m records. * * @param base * the base * @param rel * the rel * @param base_id * the base_id * @return the list */ public List<ODataRow> selectM2MRecords(OModel base, OModel rel, int base_id) { List<ODataRow> records = new ArrayList<ODataRow>(); String table = base.getTableName() + "_" + rel.getTableName() + "_rel"; String base_col = base.getTableName() + "_id"; String rel_col = rel.getTableName() + "_id"; SQLiteDatabase db = getReadableDatabase(); String where = base_col + " = ? and odoo_name = ?"; Object[] whereArgs = new Object[] { base_id, mUser.getAndroidName() }; Cursor cr = db.query(table, new String[] { "*" }, getWhereClause(where), getWhereArgs(where, whereArgs), null, null, null); List<Integer> ids = new ArrayList<Integer>(); if (cr.moveToFirst()) { do { int rel_id = cr.getInt(cr.getColumnIndex(rel_col)); ids.add(rel_id); } while (cr.moveToNext()); } cr.close(); db.close(); records.addAll(rel.select(OColumn.ROW_ID + " IN (" + StringUtils.repeat(" ?, ", ids.size() - 1) + "?)", new Object[] { ids })); return records; } /** * Creates the record row. * * @param column * the column * @param cr * the cr * @return the object */ public Object createRecordRow(OColumn column, Cursor cr) { Object value = false; if (column.getDefaultValue() != null) { value = column.getDefaultValue(); } int index = cr.getColumnIndex(column.getName()); switch (cr.getType(index)) { case Cursor.FIELD_TYPE_NULL: value = false; break; case Cursor.FIELD_TYPE_STRING: value = cr.getString(index); break; case Cursor.FIELD_TYPE_INTEGER: value = cr.getInt(index); break; case Cursor.FIELD_TYPE_FLOAT: value = cr.getFloat(index); break; case Cursor.FIELD_TYPE_BLOB: value = cr.getBlob(index); break; } return value; } /** * Truncate. * * @return true, if successful */ public boolean truncate() { delete(null, null); return true; } /** * Count. * * @return the int */ public int count() { return count(null, null); } /** * Count. * * @param where * the where * @param whereArgs * the where args * @return the int */ public int count(String where, Object[] whereArgs) { int count = 0; SQLiteDatabase db = getReadableDatabase(); String whr = getWhereClause(where); String[] args = getWhereArgs(whr, whereArgs); Cursor cr = db.query(getTableName(), new String[] { "count(*) as total" }, whr, args, null, null, null); cr.moveToFirst(); count = cr.getInt(0); cr.close(); db.close(); return count; } /** * Creates the or replace. * * @param values * the values * @return the integer */ public Integer createORReplace(OValues values) { List<OValues> vals = new ArrayList<OValues>(); vals.add(values); return createORReplace(vals).get(0); } /** * Creates the or replace. * * @param values_list * the values_list * @return the list */ public List<Integer> createORReplace(List<OValues> values_list) { List<Integer> ids = new ArrayList<Integer>(); for (OValues values : values_list) { if (!hasRecord(values.getInt("id"))) ids.add(create(values)); else { ids.add(selectRowId(values.getInt("id"))); values.put(OColumn.ROW_ID, selectRowId(values.getInt("id"))); update(values, "id = ?", new Object[] { values.getInt("id") }); } } return ids; } /** * Checks for record with server 'id' column. * * @param id * the id * @return true, if successful */ public boolean hasRecord(int id) { if (count("id = ? ", new Object[] { id }) > 0) return true; return false; } /** * Creates the. * * @param values * the values * @return the int */ public int create(OValues values) { if (!values.contains("odoo_name")) { values.put("odoo_name", mUser.getAndroidName()); } ContentValues vals = createValues(values); SQLiteDatabase db = getWritableDatabase(); db.insert(getTableName(), null, vals); db.close(); int newId = getCreateId(); values.put(OColumn.ROW_ID, newId); updateRelationColumns(values); sendDatasetChangeBroadcast(newId); notifyDataChange(newId); return newId; } /** * Update relation columns values for ManyToMany and OneToMany * * @param vals * @param newId * @return */ @SuppressWarnings("unchecked") private boolean updateRelationColumns(OValues values) { SQLiteDatabase db = getWritableDatabase(); for (OColumn column : getColumns()) { if (column.getRelationType() != null && values.contains(column.getName())) { switch (column.getRelationType()) { case ManyToMany: OModel rel_model = createInstance(column.getType()); Command command = Command.Replace; List<Integer> rel_ids = new ArrayList<Integer>(); if (values.get(column.getName()) instanceof ORelIds) { ORelIds rel_objs = (ORelIds) values.get(column.getName()); Integer base_id = rel_objs.getBaseId(); if (base_id == null) { base_id = values.getInt(OColumn.ROW_ID); } for (String key : rel_objs.keys()) { RelData data = rel_objs.get(key); command = data.getCommand(); rel_ids = new ArrayList<Integer>(); rel_ids.addAll(data.getIds()); if (command == Command.Add) { manageManyToManyRecords(db, rel_model, rel_ids, base_id, Command.Replace); } } } else { rel_ids = (List<Integer>) values.get(column.getName()); if (rel_ids == null) { rel_ids = new ArrayList<Integer>(); } manageManyToManyRecords(db, rel_model, rel_ids, values.getInt(OColumn.ROW_ID), command); } break; case OneToMany: rel_model = createInstance(column.getType()); command = Command.Replace; Integer rec_id = 0; if (values.get(column.getName()) instanceof ORelIds) { ORelIds rel_objs = (ORelIds) values.get(column.getName()); rec_id = rel_objs.getBaseId(); if (rec_id == null) { rec_id = values.getInt(OColumn.ROW_ID); } for (String key : rel_objs.keys()) { RelData data = rel_objs.get(key); command = data.getCommand(); rel_ids = new ArrayList<Integer>(); rel_ids.addAll(data.getIds()); OValues rel_vals = new OValues(); switch (command) { case Add: rel_vals.put(column.getRelatedColumn(), rec_id); break; case Delete: rel_vals.put(column.getRelatedColumn(), false); break; default: break; } String whr = OColumn.ROW_ID + " IN (" + StringUtils.repeat(" ?, ", rel_ids.size() - 1) + "?)"; Object[] args = new Object[] { rel_ids }; if (rel_ids.size() > 0) rel_model.update(rel_vals, whr, args); } } break; default: break; } } } db.close(); return true; } private void notifyDataChange(Integer id) { // FIXME: remove method after content provider ready /* * Uri uri = uri(); if (id != null) uri.buildUpon().appendPath(id + ""); * mContext.getContentResolver().notifyChange(uri, null, false); */ } private void sendDatasetChangeBroadcast(Integer newId) { Intent intent = new Intent(); intent.setAction(DataSetChangeReceiver.DATA_CHANGED); intent.putExtra("model", getModelName()); intent.putExtra("id", newId); mContext.sendBroadcast(intent); } /** * Gets the creates the id. * * @return the creates the id */ private int getCreateId() { int newId = 0; SQLiteDatabase db = getReadableDatabase(); Cursor cr = db.query("sqlite_sequence", new String[] { "name", "seq" }, "name = ?", new String[] { getTableName() }, null, null, null); if (cr.moveToFirst()) { newId = cr.getInt(cr.getColumnIndex("seq")); } cr.close(); db.close(); return newId; } /** * Update. * * @param values * the values * @param id * the id * @return the int */ public int update(OValues values, Integer id) { return update(values, OColumn.ROW_ID + " = ? ", new Object[] { id }); } /** * Update. * * @param updateValues * the update values * @param where * the where * @param whereArgs * the where args * @return the int */ public int update(OValues updateValues, String where, Object[] whereArgs) { int affectedRows = 0; ContentValues values = createValues(updateValues); SQLiteDatabase db = getWritableDatabase(); if (!updateValues.contains("is_dirty")) values.put("is_dirty", "true"); affectedRows = db.update(getTableName(), values, getWhereClause(where), getWhereArgs(where, whereArgs)); db.close(); updateRelationColumns(updateValues); notifyDataChange(null); return affectedRows; } /** * Delete. * * @param id * the id * @return true, if successful */ public boolean delete(int id) { return delete(OColumn.ROW_ID + " = ? ", new Object[] { id }); } /** * Delete. * * @param where * the where * @param whereArgs * the where args * @return true, if successful */ public boolean delete(String where, Object[] whereArgs) { return delete(where, whereArgs, false); } /** * Delete. * * @param where * the where * @param whereArgs * the where args * @param removeFromLocal * the remove from local * @return true, if successful */ public boolean delete(String where, Object[] whereArgs, boolean removeFromLocal) { Boolean deleted = false; if (removeFromLocal) { SQLiteDatabase db = getWritableDatabase(); if (db.delete(getTableName(), getWhereClause(where), getWhereArgs(where, whereArgs)) > 0) { deleted = true; } db.close(); } else { // Setting is_active to false. OValues values = new OValues(); values.put("is_dirty", "true"); values.put("is_active", "false"); if (update(values, where, whereArgs) > 0) deleted = true; } return deleted; } /** * Creates the values. * * @param db * the db * @param values * the values * @return the content values */ private ContentValues createValues(OValues values) { ContentValues vals = new ContentValues(); for (OColumn column : getColumns()) { // Checking for functional store column if (column.isFunctionalColumn() && column.canFunctionalStore()) { if ((column.checkRowId() && values.contains(OColumn.ROW_ID) || !column.checkRowId())) { int contains = 0; // getting depends column from values for (String col : column.getFunctionalStoreDepends()) if (values.contains(col)) contains++; if (contains == column.getFunctionalStoreDepends().size()) { // Getting functional value before create or update vals.put(column.getName(), getFunctionalMethodValue(column, values).toString()); } } } if (values.contains(column.getName())) { if (column.getRelationType() == null) { if (values.get(column.getName()) != null) { vals.put(column.getName(), values.get(column.getName()).toString()); } } else { switch (column.getRelationType()) { case ManyToOne: vals.put(column.getName(), values.get(column.getName()).toString()); break; default: break; } } } } vals.put("local_write_date", ODate.getDate()); return vals; } /** * Adds the many to many record. * * @param column * the column * @param base_id * the base_id * @param relation_record_id * the relation_record_id */ public void addManyToManyRecord(String column, Integer base_id, Integer relation_record_id) { List<Integer> ids = new ArrayList<Integer>(); ids.add(relation_record_id); addManyToManyRecords(column, base_id, ids); } /** * Adds the many to many records. * * @param column * the column * @param base_id * the base_id * @param relation_record_ids * the relation_record_ids */ public void addManyToManyRecords(String column, Integer base_id, List<Integer> relation_record_ids) { handleManyToManyData(column, base_id, relation_record_ids, Command.Add); } /** * Delete many to many record. * * @param column * the column * @param base_id * the base_id * @param relation_record_id * the relation_record_id */ public void deleteManyToManyRecord(String column, Integer base_id, Integer relation_record_id) { List<Integer> ids = new ArrayList<Integer>(); ids.add(relation_record_id); deleteManyToManyRecords(column, base_id, ids); } /** * Delete many to many records. * * @param column * the column * @param base_id * the base_id * @param relation_record_ids * the relation_record_ids */ public void deleteManyToManyRecords(String column, Integer base_id, List<Integer> relation_record_ids) { handleManyToManyData(column, base_id, relation_record_ids, Command.Delete); } /** * Replace many to many record. * * @param column * the column * @param base_id * the base_id * @param relation_record_id * the relation_record_id */ public void replaceManyToManyRecord(String column, Integer base_id, Integer relation_record_id) { List<Integer> ids = new ArrayList<Integer>(); ids.add(relation_record_id); replaceManyToManyRecords(column, base_id, ids); } /** * Replace many to many records. * * @param column * the column * @param base_id * the base_id * @param relation_record_ids * the relation_record_ids */ public void replaceManyToManyRecords(String column, Integer base_id, List<Integer> relation_record_ids) { handleManyToManyData(column, base_id, relation_record_ids, Command.Replace); } /** * Handle many to many data. * * @param column * the column * @param base_id * the base_id * @param relation_record_ids * the relation_record_ids * @param command * the command */ private void handleManyToManyData(String column, Integer base_id, List<Integer> relation_record_ids, Command command) { OColumn col = getColumn(column); if (col.getRelationType() == RelationType.ManyToMany) { SQLiteDatabase db = getWritableDatabase(); OModel rel_model = createInstance(col.getType()); manageManyToManyRecords(db, rel_model, relation_record_ids, base_id, command); db.close(); } } /** * Manage many to many records. * * @param db * the db * @param rel_model * the rel_model * @param ids * the ids * @param base_id * the base_id * @param command * the command */ public void manageManyToManyRecords(SQLiteDatabase db, OModel rel_model, List<Integer> ids, Integer base_id, Command command) { String table = getTableName() + "_" + rel_model.getTableName() + "_rel"; String base_column = getTableName() + "_id"; String rel_column = rel_model.getTableName() + "_id"; switch (command) { case Add: // Adding records to relation model if (ids.size() > 0) { for (int id : ids) { ContentValues values = new ContentValues(); values.put(base_column, base_id); values.put(rel_column, id); values.put("odoo_name", mUser.getAndroidName()); values.put("local_write_date", ODate.getDate()); db.insert(table, null, values); } } break; case Update: break; case Delete: // Deleting records to relation model if (ids.size() > 0) { for (int id : ids) { db.delete(table, base_column + " = ? AND " + rel_column + " = ?", new String[] { base_id + "", id + "" }); } } break; case Replace: // Removing old entries String where = base_column + " = ? "; String[] args = new String[] { base_id + "" }; db.delete(table, getWhereClause(where), getWhereArgs(where, args)); // Creating new entries manageManyToManyRecords(db, rel_model, ids, base_id, Command.Add); break; } } /** * Gets the where args. * * @param where * the where * @param whereArgs * the where args * @return the where args */ private String[] getWhereArgs(String where, Object[] whereArgs) { List<String> args = new ArrayList<String>(); if (whereArgs != null) { for (Object obj : whereArgs) { if (obj instanceof int[]) { // List<String> ids = new ArrayList<String>(); for (int id : (int[]) obj) { // ids.add(id + ""); args.add(id + ""); } // args.add(TextUtils.join(",", ids)); } else if (obj instanceof ArrayList<?>) { for (Object id : (ArrayList<?>) obj) { // ids.add(id + ""); args.add(id + ""); } // args.add(TextUtils.join("','", ids)); } else { args.add(obj.toString()); } } } args.add((mUser != null) ? mUser.getAndroidName() : ""); if (!mCheckInActiveRecord) args.add("true"); return args.toArray(new String[args.size()]); } /** * Gets the where clause. * * @param where * the where * @return the where clause */ private String getWhereClause(String where) { String newWhereClause = (where != null) ? where + " AND " : ""; if (!mCheckInActiveRecord) newWhereClause += "odoo_name = ? AND is_active = ? "; else newWhereClause += "odoo_name = ? "; return newWhereClause; } /** * Gets the sync helper. * * @return the sync helper */ public OSyncHelper getSyncHelper() { if (mSyncHelper == null) mSyncHelper = new OSyncHelper(mContext, mUser, this); mSyncingData = true; return mSyncHelper; } /** * Sets the syncing data flag. * * @param syncingData * the syncing data * @return the o model */ public OModel setSyncingDataFlag(Boolean syncingData) { mSyncingData = syncingData; return this; } /** * Gets the model values. * * @param model * the model * @return the model values */ public List<OValues> getModelValues(String model) { List<String> models = new ArrayList<String>(); models.add(model); return getModelValues(models); } /** * Gets the model values. * * @param models * the models * @return the model values */ public List<OValues> getModelValues(List<String> models) { if (mSyncHelper == null) mSyncHelper = new OSyncHelper(mContext, mUser, this); return mSyncHelper.modelInfo(models); } /** * Gets the. * * @param context * the context * @param model_name * the model_name * @return the o model */ public static OModel get(Context context, String model_name) { OModel model = null; try { PreferenceManager pfManager = new PreferenceManager(context); Class<?> model_class = Class.forName(pfManager.getString(model_name, null)); if (model_class != null) model = new OModel(context, model_name).createInstance(model_class); } catch (Exception e) { e.printStackTrace(); } return model; } /** * Checks if is empty table. * * @return true, if is empty table */ public boolean isEmptyTable() { if (count() <= 0) return true; return false; } /** * Ids. * * @return the list */ public List<Integer> ids() { List<Integer> ids = new ArrayList<Integer>(); for (ODataRow row : select()) { ids.add(row.getInt("id")); } return ids; } /** * Before create row. * * @param column * the column * @param original_record * the original_record * @return the JSON object */ public JSONObject beforeCreateRow(OColumn column, JSONObject original_record) { return original_record; } /** * Check in active record. * * @param checkInactiveRecord * the check inactive record */ public void checkInActiveRecord(Boolean checkInactiveRecord) { mCheckInActiveRecord = checkInactiveRecord; } /** * Check for local update. * * @return the boolean */ public Boolean checkForLocalUpdate() { return true; } /** * Can update to server. * * @return the boolean */ public Boolean canUpdateToServer() { return true; } /** * Can delete from server. * * @return the boolean */ public Boolean canDeleteFromServer() { return true; } /** * Can delete from local. * * @return the boolean */ public Boolean canDeleteFromLocal() { return true; } /** * Can create on server. * * @return the boolean */ public Boolean canCreateOnServer() { return true; } /** * Check for write date. * * @return the boolean */ public Boolean checkForWriteDate() { return true; } /** * Check for create date. * * @return the boolean */ public Boolean checkForCreateDate() { return true; } public Boolean checkForLocalLatestUpdate() { return true; } public OUser user() { return mUser; } public OModel setLimit(Integer limit) { mLimit = limit; return this; } public OModel setOffset(Integer offset_index) { mOffset = offset_index; return this; } public Integer getNextOffset() { return mOffset + mLimit; } public void setCreateWriteLocal(Boolean make_local) { if (make_local) { write_date.setLocalColumn(); create_date.setLocalColumn(); } } /** * browse, New API * * @return OQuery object */ public OQuery browse() { return new OQuery(mContext, this, QueryType.Select); } /** * The Class AutoUpdateOnServer. */ class AutoUpdateOnServer extends AsyncTask<Void, Void, Void> { /* * (non-Javadoc) * * @see android.os.AsyncTask#doInBackground(Params[]) */ @Override protected Void doInBackground(Void... params) { getSyncHelper().syncWithServer(); return null; } } public OContentResolver resolver() { return new OContentResolver(this, mContext); } } /** * The Interface OModelHelper. */ interface OModelHelper { /** * Gets the columns. * * @return the columns */ public List<OColumn> getColumns(); /** * Gets the columns. * * @param local * the local * @return the columns */ public List<OColumn> getColumns(Boolean local); /** * Default domain. * * @return the o domain */ public ODomain defaultDomain(); }