com.odoo.core.service.OSyncDataUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.odoo.core.service.OSyncDataUtils.java

Source

/**
 * 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/>
 *
 * Created on 2/1/15 4:15 PM
 */
package com.odoo.core.service;

import android.content.Context;
import android.content.SyncResult;
import android.util.Log;

import com.odoo.core.orm.ODataRow;
import com.odoo.core.orm.OModel;
import com.odoo.core.orm.OValues;
import com.odoo.core.orm.fields.OColumn;
import com.odoo.core.support.OUser;
import com.odoo.core.support.OdooFields;
import com.odoo.core.utils.JSONUtils;
import com.odoo.core.utils.ODateUtils;
import com.odoo.core.utils.OListUtils;
import com.odoo.core.utils.StringUtils;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import odoo.ODomain;
import odoo.Odoo;

public class OSyncDataUtils {
    public static final String TAG = OSyncDataUtils.class.getSimpleName();
    private Context mContext;
    private OModel mModel;
    private OUser mUser;
    private JSONObject response;
    private HashSet<String> recordsId = new HashSet<>();
    private HashMap<String, SyncRelationRecords> relationRecordsHashMap = new HashMap<>();
    private Odoo mOdoo;
    private SyncResult mResult;
    private HashMap<String, List<Integer>> updateToServerRecords = new HashMap<>();
    private Boolean mCreateRelationRecords = true;

    public OSyncDataUtils(Context context, Odoo odoo, OModel model, OUser user, JSONObject response,
            SyncResult result, Boolean createRelRecord) {
        mContext = context;
        mOdoo = odoo;
        mModel = model;
        mUser = user;
        this.response = response;
        mResult = result;
        mCreateRelationRecords = createRelRecord;
        JSONArray updateInLocal = checkLocalUpdatedRecords();
        handleResult(updateInLocal);
    }

    private JSONArray checkLocalUpdatedRecords() {
        // Array of records which are new or need to update in local
        JSONArray finalRecords = new JSONArray();
        try {
            // Getting list of ids which are present in local database
            List<Integer> serverIds = new ArrayList<>();
            HashMap<String, JSONObject> serverIdRecords = new HashMap<>();
            JSONArray records = response.getJSONArray("records");
            for (int i = 0; i < records.length(); i++) {
                JSONObject record = records.getJSONObject(i);
                if (mModel.hasServerRecord(record.getInt("id"))
                        && mModel.isServerRecordDirty(record.getInt("id"))) {
                    int server_id = record.getInt("id");
                    serverIds.add(server_id);
                    serverIdRecords.put("key_" + server_id, record);
                } else {
                    finalRecords.put(record);
                }
            }

            // getting local dirty records if server records length = 0
            if (records.length() <= 0) {
                for (ODataRow row : mModel.select(new String[] {}, "_is_dirty = ? and _is_active = ? and id != ?",
                        new String[] { "true", "true", "0" })) {
                    serverIds.add(row.getInt("id"));
                }
            }
            // Comparing dirty (updated) record
            List<Integer> updateToServerIds = new ArrayList<>();
            if (serverIds.size() > 0) {
                HashMap<String, String> write_dates = getWriteDate(mModel, serverIds);
                for (Integer server_id : serverIds) {
                    String key = "key_" + server_id;
                    String write_date = write_dates.get(key);
                    ODataRow record = mModel.browse(new String[] { "_write_date" }, "id = ?",
                            new String[] { server_id + "" });
                    if (record != null) {
                        Date write_date_obj = ODateUtils.createDateObject(write_date, ODateUtils.DEFAULT_FORMAT,
                                false);
                        Date _write_date_obj = ODateUtils.createDateObject(record.getString("_write_date"),
                                ODateUtils.DEFAULT_FORMAT, false);
                        if (_write_date_obj.compareTo(write_date_obj) > 0) {
                            // Local record is latest
                            updateToServerIds.add(server_id);
                        } else {
                            if (serverIdRecords.containsKey(key)) {
                                finalRecords.put(serverIdRecords.get(key));
                            }
                        }
                    }
                }
            }
            if (updateToServerIds.size() > 0) {
                updateToServerRecords.put(mModel.getModelName(), updateToServerIds);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return finalRecords;
    }

    private HashMap<String, String> getWriteDate(OModel model, List<Integer> ids) {
        HashMap<String, String> map = new HashMap<>();
        try {
            JSONArray result;
            if (model.getColumn("write_date") != null) {
                OdooFields fields = new OdooFields(new String[] { "write_date" });
                ODomain domain = new ODomain();
                domain.add("id", "in", ids);
                JSONObject data = mOdoo.search_read(model.getModelName(), fields.get(), domain.get());
                result = data.getJSONArray("records");
            } else {
                JSONObject data = mOdoo.perm_read(model.getModelName(), ids);
                result = data.getJSONArray("result");
            }

            if (result.length() > 0) {
                for (int i = 0; i < result.length(); i++) {
                    JSONObject obj = result.getJSONObject(i);
                    map.put("key_" + obj.getInt("id"), obj.getString("write_date"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    private void handleResult(JSONArray records) {
        try {
            recordsId.clear();
            int length = records.length();
            int counter = 0;
            List<OColumn> columns = mModel.getColumns(false);
            columns.addAll(mModel.getFunctionalColumns());
            for (int i = 0; i < length; i++) {
                JSONObject record = records.getJSONObject(i);
                OValues values = new OValues();
                recordsId.add(mModel.getModelName() + "_" + record.getInt("id"));
                for (OColumn column : columns) {
                    String name = column.getName();
                    if (column.getRelationType() == null) {

                        // checks for functional store fields
                        if (column.isFunctionalColumn() && column.canFunctionalStore()) {
                            List<String> depends = column.getFunctionalStoreDepends();
                            OValues dependValues = new OValues();
                            if (!column.isLocal())
                                dependValues.put(column.getName(), record.get(column.getName()));
                            for (String depend : depends) {
                                if (record.has(depend)) {
                                    dependValues.put(depend, record.get(depend));
                                }
                            }
                            Object value = mModel.getFunctionalMethodValue(column, dependValues);
                            values.put(column.getName(), value);
                        } else {
                            // Normal Columns
                            values.put(name, record.get(name));
                        }
                    } else {
                        // Relation Columns
                        if (!(record.get(name) instanceof Boolean)) {
                            switch (column.getRelationType()) {
                            case ManyToOne:
                                JSONArray m2oData = record.getJSONArray(name);
                                OModel m2o_model = mModel.createInstance(column.getType());
                                String recKey = m2o_model.getModelName() + "_" + m2oData.get(0);
                                int m2oRowId;
                                if (!recordsId.contains(recKey)) {
                                    OValues m2oValue = new OValues();
                                    m2oValue.put("id", m2oData.get(0));
                                    m2oValue.put(m2o_model.getDefaultNameColumn(), m2oData.get(1));
                                    m2oValue.put("_is_dirty", "false");
                                    m2oRowId = m2o_model.insertOrUpdate(m2oData.getInt(0), m2oValue);
                                } else {
                                    m2oRowId = m2o_model.selectRowId(m2oData.getInt(0));
                                }

                                values.put(name, m2oRowId);
                                if (mCreateRelationRecords) {
                                    // Add id to sync if model contains more than (id,name) columns
                                    if (m2o_model.getColumns(false).size() > 2
                                            || (m2o_model.getColumns(false).size() > 4
                                                    && mModel.getOdooVersion().getVersion_number() > 7)) {
                                        List<Integer> m2oIds = new ArrayList<>();
                                        m2oIds.add(m2oData.getInt(0));
                                        addUpdateRelationRecord(mModel, m2o_model.getTableName(), column.getType(),
                                                name, null, column.getRelationType(), m2oIds);
                                    }
                                }
                                m2o_model.close();
                                break;
                            case ManyToMany:
                                OModel m2mModel = mModel.createInstance(column.getType());
                                List<Integer> m2mIds = JSONUtils.<Integer>toList(record.getJSONArray(name));
                                if (mCreateRelationRecords) {
                                    addUpdateRelationRecord(mModel, m2mModel.getTableName(), column.getType(), name,
                                            null, column.getRelationType(),
                                            (column.getRecordSyncLimit() > 0)
                                                    ? m2mIds.subList(0, column.getRecordSyncLimit())
                                                    : m2mIds);
                                }
                                List<Integer> m2mRowIds = new ArrayList<>();
                                for (Integer id : m2mIds) {
                                    recKey = m2mModel.getModelName() + "_" + id;
                                    int r_id;
                                    if (!recordsId.contains(recKey)) {
                                        OValues m2mValues = new OValues();
                                        m2mValues.put("id", id);
                                        m2mValues.put("_is_dirty", "false");
                                        r_id = m2mModel.insertOrUpdate(id, m2mValues);
                                    } else {
                                        r_id = m2mModel.selectRowId(id);
                                    }
                                    m2mRowIds.add(r_id);
                                }
                                if (m2mRowIds.size() > 0) {
                                    // Putting many to many related ids
                                    // (generated _id for each of server ids)
                                    values.put(name, m2mRowIds);
                                }
                                m2mModel.close();
                                break;
                            case OneToMany:
                                if (mCreateRelationRecords) {
                                    OModel o2mModel = mModel.createInstance(column.getType());
                                    List<Integer> o2mIds = JSONUtils.<Integer>toList(record.getJSONArray(name));
                                    addUpdateRelationRecord(mModel, o2mModel.getTableName(), column.getType(), name,
                                            column.getRelatedColumn(), column.getRelationType(),
                                            (column.getRecordSyncLimit() > 0)
                                                    ? o2mIds.subList(0, column.getRecordSyncLimit())
                                                    : o2mIds);
                                    o2mModel.close();
                                }
                                break;
                            }
                        }
                    }
                }
                // Some default values
                values.put("id", record.getInt("id"));
                values.put("_write_date", ODateUtils.getUTCDate());
                values.put("_is_active", "true");
                values.put("_is_dirty", "false");
                mModel.insertOrUpdate(record.getInt("id"), values);
                counter++;
            }
            Log.i(TAG, counter + " records affected");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean updateRecordsOnServer(OSyncAdapter adapter) {
        try {
            // Use key (modal name) from updateToServerRecords
            // use updateToServerRecords ids
            int counter = 0;
            for (String key : updateToServerRecords.keySet()) {
                OModel model = OModel.get(mContext, key, mUser.getAndroidName());
                List<String> ids = OListUtils.toStringList(updateToServerRecords.get(key));
                counter += ids.size();
                for (ODataRow record : model.select(null,
                        "id IN ( " + StringUtils.repeat("?, ", ids.size() - 1) + " ?)",
                        ids.toArray(new String[ids.size()]))) {

                    if (adapter.validateRelationRecords(model, record)) {
                        mOdoo.updateValues(model.getModelName(), JSONUtils.createJSONValues(model, record),
                                record.getInt("id"));
                        OValues value = new OValues();
                        value.put("_is_dirty", "false");
                        value.put("_write_date", ODateUtils.getUTCDate());
                        model.update(record.getInt(OColumn.ROW_ID), value);
                        model.close();
                    }
                }
            }
            Log.i(TAG, counter + " records updated on server");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    private void addUpdateRelationRecord(OModel baseModel, String relTable, Class<?> model, String column,
            String relatedColumn, OColumn.RelationType type, List<Integer> ids) {
        String key = relTable + "_" + column;
        if (relationRecordsHashMap.containsKey(key)) {
            SyncRelationRecords data = relationRecordsHashMap.get(key);
            data.updateIds(ids);
            relationRecordsHashMap.put(key, data);
        } else {
            relationRecordsHashMap.put(key,
                    new SyncRelationRecords(baseModel, model, column, relatedColumn, type, ids));
        }
    }

    public HashMap<String, SyncRelationRecords> getRelationRecordsHashMap() {
        if (mCreateRelationRecords)
            return relationRecordsHashMap;
        return new HashMap<>();
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        if (mModel != null)
            mModel.close();
    }

    public static class SyncRelationRecords {
        private OModel baseModel;
        private Class<?> relationModel;
        private String relationColumn;
        private String relatedColumn;
        private OColumn.RelationType relationType;
        private List<Integer> serverIds = new ArrayList<>();

        public SyncRelationRecords(OModel baseModel, Class<?> relationModel, String relationColumn,
                String relatedColumn, OColumn.RelationType relationType, List<Integer> serverIds) {
            this.baseModel = baseModel;
            this.relationModel = relationModel;
            this.relationColumn = relationColumn;
            this.relatedColumn = relatedColumn;
            this.relationType = relationType;
            this.serverIds.addAll(serverIds);
        }

        public OModel getBaseModel() {
            return baseModel;
        }

        public void setBaseModel(OModel baseModel) {
            this.baseModel = baseModel;
        }

        public Class<?> getRelationModel() {
            return relationModel;
        }

        public void setRelationModel(Class<?> relationModel) {
            this.relationModel = relationModel;
        }

        public String getRelationColumn() {
            return relationColumn;
        }

        public void setRelationColumn(String relationColumn) {
            this.relationColumn = relationColumn;
        }

        public String getRelatedColumn() {
            return relatedColumn;
        }

        public void setRelatedColumn(String relatedColumn) {
            this.relatedColumn = relatedColumn;
        }

        public OColumn.RelationType getRelationType() {
            return relationType;
        }

        public void setRelationType(OColumn.RelationType relationType) {
            this.relationType = relationType;
        }

        public List<Integer> getServerIds() {
            return serverIds;
        }

        public void setServerIds(List<Integer> serverIds) {
            this.serverIds.clear();
            this.serverIds.addAll(serverIds);
        }

        public void updateIds(List<Integer> ids) {
            this.serverIds.addAll(ids);
        }

        public List<Integer> getUniqueIds() {
            List<Integer> ids = new ArrayList<>();
            HashSet<Integer> uIds = new HashSet<>(serverIds);
            ids.addAll(uIds);
            return ids;
        }
    }

}