You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
git.text/src/gtask/data/SqlData.java

306 lines
9.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.gtask.data;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
import net.micode.notes.gtask.exception.ActionFailureException;
import org.json.JSONException;
import org.json.JSONObject;
/**
* <p>SQL数据操作类用于处理便签数据的增删改查操作。</p>
* <p>设计意图作为Google任务同步与本地数据库之间的数据操作桥梁封装对ContentProvider的访问。</p>
* <p>核心职责:</p>
* <ul>
* <li>从Cursor加载数据</li>
* <li>与JSON数据格式的相互转换</li>
* <li>将数据变更提交到ContentProvider</li>
* <li>跟踪数据变更差异</li>
* </ul>
*/
public class SqlData {
private static final String TAG = SqlData.class.getSimpleName();
/**
* 无效ID常量
*/
private static final int INVALID_ID = -99999;
/**
* 数据查询投影列
*/
public static final String[] PROJECTION_DATA = new String[] {
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA3
};
/**
* 数据ID列索引
*/
public static final int DATA_ID_COLUMN = 0;
/**
* 数据MIME类型列索引
*/
public static final int DATA_MIME_TYPE_COLUMN = 1;
/**
* 数据内容列索引
*/
public static final int DATA_CONTENT_COLUMN = 2;
/**
* 数据内容DATA1列索引
*/
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
/**
* 数据内容DATA3列索引
*/
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
/**
* 内容解析器用于访问ContentProvider
*/
private ContentResolver mContentResolver;
/**
* 是否为新创建的数据
*/
private boolean mIsCreate;
/**
* 数据ID
*/
private long mDataId;
/**
* 数据MIME类型
*/
private String mDataMimeType;
/**
* 数据内容
*/
private String mDataContent;
/**
* 数据内容DATA1字段
*/
private long mDataContentData1;
/**
* 数据内容DATA3字段
*/
private String mDataContentData3;
/**
* 数据变更差异集合
*/
private ContentValues mDiffDataValues;
/**
* <p>构造方法创建新的SqlData对象。</p>
*
* @param context 上下文对象
*/
public SqlData(Context context) {
mContentResolver = context.getContentResolver();
mIsCreate = true;
mDataId = INVALID_ID;
mDataMimeType = DataConstants.NOTE;
mDataContent = "";
mDataContentData1 = 0;
mDataContentData3 = "";
mDiffDataValues = new ContentValues();
}
/**
* <p>构造方法从Cursor创建SqlData对象。</p>
*
* @param context 上下文对象
* @param c 包含数据的Cursor对象
*/
public SqlData(Context context, Cursor c) {
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDiffDataValues = new ContentValues();
}
/**
* <p>从Cursor加载数据到当前对象。</p>
*
* @param c 包含数据的Cursor对象
*/
private void loadFromCursor(Cursor c) {
mDataId = c.getLong(DATA_ID_COLUMN);
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
mDataContent = c.getString(DATA_CONTENT_COLUMN);
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
}
/**
* <p>从JSON对象设置数据内容。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>从JSON对象中提取各个字段的值</li>
* <li>比较当前值与新值,仅在不同时更新差异集合</li>
* <li>更新当前对象的字段值</li>
* </ul>
*
* @param js 包含数据的JSON对象
* @throws JSONException 如果JSON解析失败
*/
public void setContent(JSONObject js) throws JSONException {
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;
if (mIsCreate || mDataId != dataId) {
mDiffDataValues.put(DataColumns.ID, dataId);
}
mDataId = dataId;
String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)
: DataConstants.NOTE;
if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {
mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType);
}
mDataMimeType = dataMimeType;
String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";
if (mIsCreate || !mDataContent.equals(dataContent)) {
mDiffDataValues.put(DataColumns.CONTENT, dataContent);
}
mDataContent = dataContent;
long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;
if (mIsCreate || mDataContentData1 != dataContentData1) {
mDiffDataValues.put(DataColumns.DATA1, dataContentData1);
}
mDataContentData1 = dataContentData1;
String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";
if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {
mDiffDataValues.put(DataColumns.DATA3, dataContentData3);
}
mDataContentData3 = dataContentData3;
}
/**
* <p>获取当前数据的JSON表示。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>检查数据是否已创建</li>
* <li>创建JSON对象并设置各个字段值</li>
* <li>返回JSON对象</li>
* </ul>
*
* @return 包含数据的JSON对象若数据未创建则返回null
* @throws JSONException 如果JSON创建失败
*/
public JSONObject getContent() throws JSONException {
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
JSONObject js = new JSONObject();
js.put(DataColumns.ID, mDataId);
js.put(DataColumns.MIME_TYPE, mDataMimeType);
js.put(DataColumns.CONTENT, mDataContent);
js.put(DataColumns.DATA1, mDataContentData1);
js.put(DataColumns.DATA3, mDataContentData3);
return js;
}
/**
* <p>提交数据变更到ContentProvider。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>如果是新创建的数据,执行插入操作</li>
* <li>如果是已存在的数据,执行更新操作</li>
* <li>支持版本验证,避免并发更新冲突</li>
* <li>更新操作完成后清空差异集合</li>
* </ul>
*
* @param noteId 所属便签ID
* @param validateVersion 是否验证版本
* @param version 版本号
* @throws ActionFailureException 如果操作失败
*/
public void commit(long noteId, boolean validateVersion, long version) {
if (mIsCreate) {
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID);
}
mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try {
mDataId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
} else {
if (mDiffDataValues.size() > 0) {
int result = 0;
if (!validateVersion) {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);
} else {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues,
" ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.VERSION + "=?)", new String[] {
String.valueOf(noteId), String.valueOf(version)
});
}
if (result == 0) {
Log.w(TAG, "there is no update. maybe user updates note when syncing");
}
}
}
mDiffDataValues.clear();
mIsCreate = false;
}
/**
* <p>获取数据ID。</p>
*
* @return 数据ID
*/
public long getId() {
return mDataId;
}
}