com.odoo.support.provider.OContentProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.odoo.support.provider.OContentProvider.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/>
 * 
 */

package com.odoo.support.provider;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

import org.json.JSONArray;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

import com.odoo.orm.OColumn;
import com.odoo.orm.OColumn.RelationType;
import com.odoo.orm.OModel;
import com.odoo.orm.OModel.Command;
import com.odoo.orm.SelectionBuilder;
import com.odoo.util.JSONUtils;

/**
 * The Class OContentProvider.
 */
public abstract class OContentProvider extends ContentProvider implements OContentProviderHelper {

    private final int COLLECTION = 1;

    private final int SINGLE_ROW = 2;

    private UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

    /** The database model. */
    private OModel model = null;

    public static Uri buildURI(String authority, String path) {
        Uri.Builder uriBuilder = new Uri.Builder();
        uriBuilder.authority(authority);
        uriBuilder.appendPath(path);
        uriBuilder.scheme("content");
        return uriBuilder.build();
    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        reInitModel();
        final SQLiteDatabase db = model.getWritableDatabase();
        assert db != null;
        final int match = matcher.match(uri);
        int count = 0;
        SelectionBuilder builder = new SelectionBuilder();
        switch (match) {
        case COLLECTION:
            count = builder.table(model.getTableName()).where(where, whereArgs).delete(db);
            break;
        case SINGLE_ROW:
            String id = uri.getLastPathSegment();
            count = builder.table(model.getTableName()).where(OColumn.ROW_ID + "=?", id).where(where, whereArgs)
                    .delete(db);
            break;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        // Send broadcast to registered ContentObservers, to refresh UI.
        Context ctx = getContext();
        assert ctx != null;
        ctx.getContentResolver().notifyChange(uri, null, false);
        return count;
    }

    @Override
    public String getType(Uri uri) {
        return uri().toString();
    }

    private void handleManyToMany(HashMap<String, List<Integer>> record_ids, int _id) {
        if (record_ids.size() > 0) {
            for (String key : record_ids.keySet()) {
                List<Integer> ids = record_ids.get(key);
                OColumn column = model.getColumn(key);
                OModel rel_model = model.createInstance(column.getType());
                model.manageManyToManyRecords(model.getWritableDatabase(), rel_model, ids, _id, Command.Replace);
            }
        }
    }

    private HashMap<String, List<Integer>> getManyToManyRecords(ContentValues values) {
        HashMap<String, List<Integer>> ids = new HashMap<String, List<Integer>>();
        for (OColumn col : model.getRelationColumns()) {
            if (col.getRelationType() == RelationType.ManyToMany) {
                if (values.containsKey(col.getName())) {
                    List<Integer> record_ids = new ArrayList<Integer>();
                    try {
                        record_ids.addAll(
                                JSONUtils.<Integer>toList(new JSONArray(values.get(col.getName()).toString())));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    ids.put(col.getName(), record_ids);
                    values.remove(col.getName());
                }
            }
        }
        return ids;
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        reInitModel();
        HashMap<String, List<Integer>> manyToManyIds = getManyToManyRecords(initialValues);
        final SQLiteDatabase db = model.getWritableDatabase();
        assert db != null;
        final int match = matcher.match(uri);
        Uri result;
        switch (match) {
        case COLLECTION:
            long id = db.insertOrThrow(model.getTableName(), null, initialValues);
            handleManyToMany(manyToManyIds, (int) id);
            result = Uri.parse(uri() + "/" + id);
            break;
        case SINGLE_ROW:
            throw new UnsupportedOperationException("Insert not supported on URI: " + uri);
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        // Send broadcast to registered ContentObservers, to refresh UI.
        Context ctx = getContext();
        assert ctx != null;
        ctx.getContentResolver().notifyChange(uri, null, false);
        return result;
    }

    @Override
    public boolean onCreate() {
        model = model(getContext());
        matcher.addURI(authority(), path(), COLLECTION);
        matcher.addURI(authority(), path() + "/#", SINGLE_ROW);
        return ((model == null) ? false : true);
    }

    public void addURI(String authority, String path, int type) {
        matcher.addURI(authority, path, type);
    }

    private void reInitModel() {
        if (model.getDatabaseName().length() == 0) {
            onCreate();
        }
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) {
        projection = validateProjections(projection);
        Cursor c = createQuery(uri, projection, selection, selectionArgs, sort);
        Context ctx = getContext();
        assert ctx != null;
        c.setNotificationUri(ctx.getContentResolver(), uri);
        return c;
    }

    @Override
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        reInitModel();
        SelectionBuilder builder = new SelectionBuilder();
        final SQLiteDatabase db = model.getWritableDatabase();
        final int match = matcher.match(uri);
        int count;
        switch (match) {
        case COLLECTION:
            Cursor cr = query(uri, new String[] { OColumn.ROW_ID }, where, whereArgs, null);
            while (cr.moveToNext()) {
                int id = cr.getInt(cr.getColumnIndex(OColumn.ROW_ID));
                handleManyToMany(getManyToManyRecords(values), id);
            }
            cr.close();

            count = builder.table(model.getTableName()).where(where, whereArgs).update(db, values);
            break;
        case SINGLE_ROW:
            String id = uri.getLastPathSegment();
            handleManyToMany(getManyToManyRecords(values), Integer.parseInt(id));
            count = builder.table(model.getTableName()).where(where, whereArgs).where(OColumn.ROW_ID + "=?", id)
                    .where(where, whereArgs).update(db, values);
            break;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        Context ctx = getContext();
        assert ctx != null;
        ctx.getContentResolver().notifyChange(uri, null, false);
        return count;
    }

    private String[] validateProjections(String[] projection) {
        List<String> columns = new ArrayList<String>();
        columns.addAll(Arrays.asList(projection));
        columns.addAll(Arrays.asList(new String[] { OColumn.ROW_ID, "is_dirty", "is_active", "odoo_name" }));
        if (model.getColumn("id") != null)
            columns.add("id");
        return columns.toArray(new String[columns.size()]);
    }

    private Cursor createQuery(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sort) {
        reInitModel();
        SQLiteQueryBuilder query = new SQLiteQueryBuilder();
        boolean withAlias = (projection.length < model.projection().length);
        StringBuffer joins = new StringBuffer();
        String base_table = model.getTableName();
        String base_alias = base_table + "_base";
        HashMap<String, String> projectionMap = new HashMap<String, String>();
        List<String> mJoinTables = new ArrayList<String>();
        for (String col_name : projection) {
            String col = col_name;
            if (col_name.contains(".")) {
                col = col_name.split("\\.")[0];
            }
            OColumn column = model.getColumn(col);
            String display_col = col;
            if (withAlias) {
                display_col = base_alias + "." + col + " AS " + col;
                boolean many2oneJoin = col_name.contains(".");
                if (column.getRelationType() != null && many2oneJoin) {
                    OModel rel_model = model.createInstance(column.getType());
                    String table = rel_model.getTableName();
                    String alias = table;
                    alias = table + "_self";
                    table += " AS " + alias;
                    if (!mJoinTables.contains(alias)) {
                        mJoinTables.add(alias);
                        joins.append(" JOIN ");
                        joins.append(table);
                        joins.append(" ON ");
                        joins.append(base_alias + "." + column.getName());
                        joins.append(" = ");
                        joins.append(alias + "." + OColumn.ROW_ID);
                        joins.append(" ");
                    }
                    String rel_col = col;
                    String rel_col_name = "";
                    if (col_name.contains(".")) {
                        rel_col += "_" + col_name.split("\\.")[1];
                        rel_col_name = col_name.split("\\.")[1];
                    }
                    projectionMap.put(rel_col, alias + "." + rel_col_name + " AS " + rel_col);
                }
            }
            projectionMap.put(col, display_col);
        }
        StringBuffer tables = new StringBuffer();
        tables.append(base_table + ((withAlias) ? " AS " + base_alias : " "));
        tables.append(joins.toString());
        query.setTables(tables.toString());
        query.setProjectionMap(projectionMap);
        StringBuffer whr = new StringBuffer();
        String where = null;
        if (selection != null && selectionArgs != null) {
            if (withAlias) {
                // Check for and
                Pattern pattern = Pattern.compile(" and | AND ");
                String[] data = pattern.split(selection);
                StringBuffer or_string = new StringBuffer();
                for (String token : data) {
                    if (token.contains("OR") || token.contains("or")) {
                        or_string.append(token.trim());
                        or_string.append(" OR ");
                    } else {
                        whr.append(base_alias + "." + token.trim());
                        whr.append(" AND ");
                    }
                }
                if (whr.length() > 0)
                    whr.delete(whr.length() - 5, whr.length());
                // Check for or
                if (or_string.length() > 0) {
                    if (whr.length() > 0)
                        whr.append(" AND ");
                    pattern = Pattern.compile(" or | OR ");
                    data = pattern.split(or_string.toString());
                    for (String token : data) {
                        if (!token.contains(base_alias)) {
                            if (token.contains("(")) {
                                whr.append("(");
                                token = token.replaceAll("\\(", "");
                                whr.append(base_alias + "." + token.trim());
                            } else if (token.contains(")")) {
                                token = token.replaceAll("\\)", "");
                                whr.append(base_alias + "." + token.trim());
                                whr.append(")");
                            } else {
                                whr.append(base_alias + "." + token.trim());
                            }
                        } else {
                            whr.append(token.trim());
                        }
                        whr.append(" OR ");
                    }
                    if (whr.length() > 0)
                        whr.delete(whr.length() - 4, whr.length());
                }
            } else {
                whr.append(selection);
            }
            where = whr.toString();
        }
        Cursor c = null;
        int uriMatch = matcher.match(uri);
        switch (uriMatch) {
        case SINGLE_ROW:
            // Return a single entry, by ID.
            String id = uri.getLastPathSegment();
            query.appendWhere(base_alias + "." + OColumn.ROW_ID + " = " + id);
        case COLLECTION:
            c = query.query(model.getReadableDatabase(), null, where, selectionArgs, null, null, sort);
            return c;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

    public int matchURI(Uri uri) {
        return matcher.match(uri);
    }

    public OModel getModel() {
        return model;
    }

}