Android Open Source - android-sqlite-server Cursor To Bulk Cursor Adaptor






From Project

Back to project page android-sqlite-server.

License

The source code is released under:

Apache License

If you think the Android project android-sqlite-server listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2006 The Android Open Source Project
 *//from   w w  w .ja v  a  2s .c  om
 * 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 aosp.android.database;

import android.database.*;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;


/**
 * Wraps a BulkCursor around an existing Cursor making it remotable.
 * <p>
 * If the wrapped cursor returns non-null from {@link CrossProcessCursor#getWindow}
 * then it is assumed to own the window.  Otherwise, the adaptor provides a
 * window to be filled and ensures it gets closed as needed during deactivation
 * and requeries.
 * </p>
 *
 * {@hide}
 */
public final class CursorToBulkCursorAdaptor extends BulkCursorNative 
        implements IBinder.DeathRecipient {
    private static final String TAG = "Cursor";

    private final Object mLock = new Object();
    private final String mProviderName;
    private ContentObserverProxy mObserver;

    /**
     * The cursor that is being adapted.
     * This field is set to null when the cursor is closed.
     */
    private CrossProcessCursor mCursor;

    /**
     * The cursor window that was filled by the cross process cursor in the
     * case where the cursor does not support getWindow.
     * This field is only ever non-null when the window has actually be filled.
     */
    private CursorWindow mFilledWindow;

    private static final class ContentObserverProxy extends ContentObserver {
        protected IContentObserver mRemote;

        public ContentObserverProxy(IContentObserver remoteObserver, DeathRecipient recipient) {
            super(null);
            mRemote = remoteObserver;
            try {
                remoteObserver.asBinder().linkToDeath(recipient, 0);
            } catch (RemoteException e) {
                // Do nothing, the far side is dead
            }
        }
        
        public boolean unlinkToDeath(DeathRecipient recipient) {
            return mRemote.asBinder().unlinkToDeath(recipient, 0);
        }

        @Override
        public boolean deliverSelfNotifications() {
            // The far side handles the self notifications.
            return false;
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            try {
                mRemote.onChange(selfChange, uri);
            } catch (RemoteException ex) {
                // Do nothing, the far side is dead
            }
        }
    }

    public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer,
            String providerName) {
        if (cursor instanceof CrossProcessCursor) {
            mCursor = (CrossProcessCursor)cursor;
        } else {
            mCursor = new CrossProcessCursorWrapper(cursor);
        }
        mProviderName = providerName;

        synchronized (mLock) {
            createAndRegisterObserverProxyLocked(observer);
        }
    }

    private void closeFilledWindowLocked() {
        if (mFilledWindow != null) {
            mFilledWindow.close();
            mFilledWindow = null;
        }
    }

    private void disposeLocked() {
        if (mCursor != null) {
            unregisterObserverProxyLocked();
            mCursor.close();
            mCursor = null;
        }

        closeFilledWindowLocked();
    }

    private void throwIfCursorIsClosed() {
        if (mCursor == null) {
            throw new StaleDataException("Attempted to access a cursor after it has been closed.");
        }
    }

    @Override
    public void binderDied() {
        synchronized (mLock) {
            disposeLocked();
        }
    }

    public BulkCursorDescriptor getBulkCursorDescriptor() {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            BulkCursorDescriptor d = new BulkCursorDescriptor();
            d.cursor = this;
            d.columnNames = mCursor.getColumnNames();
            d.wantsAllOnMoveCalls = mCursor.getWantsAllOnMoveCalls();
            d.count = mCursor.getCount();
            d.window = mCursor.getWindow();
            if (d.window != null) {
                // Acquire a reference to the window because its reference count will be
                // decremented when it is returned as part of the binder call reply parcel.
                d.window.acquireReference();
            }
            return d;
        }
    }

    @Override
    public CursorWindow getWindow(int position) {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            if (!mCursor.moveToPosition(position)) {
                closeFilledWindowLocked();
                return null;
            }

            CursorWindow window = mCursor.getWindow();
            if (window != null) {
                closeFilledWindowLocked();
            } else {
                window = mFilledWindow;
                if (window == null) {
                    mFilledWindow = new CursorWindow(mProviderName);
                    window = mFilledWindow;
                } else if (position < window.getStartPosition()
                        || position >= window.getStartPosition() + window.getNumRows()) {
                    window.clear();
                }
                mCursor.fillWindow(position, window);
            }

            if (window != null) {
                // Acquire a reference to the window because its reference count will be
                // decremented when it is returned as part of the binder call reply parcel.
                window.acquireReference();
            }
            return window;
        }
    }

    @Override
    public void onMove(int position) {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            mCursor.onMove(mCursor.getPosition(), position);
        }
    }

    @Override
    public void deactivate() {
        synchronized (mLock) {
            if (mCursor != null) {
                unregisterObserverProxyLocked();
                mCursor.deactivate();
            }

            closeFilledWindowLocked();
        }
    }

    @Override
    public void close() {
        synchronized (mLock) {
            disposeLocked();
        }
    }

    @Override
    public int requery(IContentObserver observer) {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            closeFilledWindowLocked();

            try {
                if (!mCursor.requery()) {
                    return -1;
                }
            } catch (IllegalStateException e) {
                IllegalStateException leakProgram = new IllegalStateException(
                        mProviderName + " Requery misuse db, mCursor isClosed:" +
                        mCursor.isClosed(), e);
                throw leakProgram;
            }

            unregisterObserverProxyLocked();
            createAndRegisterObserverProxyLocked(observer);
            return mCursor.getCount();
        }
    }

    /**
     * Create a ContentObserver from the observer and register it as an observer on the
     * underlying cursor.
     * @param observer the IContentObserver that wants to monitor the cursor
     * @throws IllegalStateException if an observer is already registered
     */
    private void createAndRegisterObserverProxyLocked(IContentObserver observer) {
        if (mObserver != null) {
            throw new IllegalStateException("an observer is already registered");
        }
        mObserver = new ContentObserverProxy(observer, this);
        mCursor.registerContentObserver(mObserver);
    }

    /** Unregister the observer if it is already registered. */
    private void unregisterObserverProxyLocked() {
        if (mObserver != null) {
            mCursor.unregisterContentObserver(mObserver);
            mObserver.unlinkToDeath(this);
            mObserver = null;
        }
    }

    @Override
    public Bundle getExtras() {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            return mCursor.getExtras();
        }
    }

    @Override
    public Bundle respond(Bundle extras) {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            return mCursor.respond(extras);
        }
    }
}




Java Source Code List

aosp.android.database.BulkCursorDescriptor.java
aosp.android.database.BulkCursorNative.java
aosp.android.database.BulkCursorToCursorAdaptor.java
aosp.android.database.CrossProcessCursorWrapper.java
aosp.android.database.CursorToBulkCursorAdaptor.java
aosp.android.database.IBulkCursor.java
aosp.android.database.MoreDatabaseUtils.java
org.devtcg.sqliteserver.SQLiteContentProviderServer.java
org.devtcg.sqliteserver.SQLiteServerConnectionManager.java
org.devtcg.sqliteserver.SQLiteServerConnection.java
org.devtcg.sqliteserver.SQLiteServer.java
org.devtcg.sqliteserver.SQLiteServiceServer.java
org.devtcg.sqliteserver.exception.SQLiteServerException.java
org.devtcg.sqliteserver.impl.ExecutorHelper.java
org.devtcg.sqliteserver.impl.SQLiteExecutor.java
org.devtcg.sqliteserver.impl.ServerImplProvider.java
org.devtcg.sqliteserver.impl.binder.AbstractBinderClient.java
org.devtcg.sqliteserver.impl.binder.BinderHandle.java
org.devtcg.sqliteserver.impl.binder.BundleUtils.java
org.devtcg.sqliteserver.impl.binder.ClientTransactor.java
org.devtcg.sqliteserver.impl.binder.ContentObserverProxy.java
org.devtcg.sqliteserver.impl.binder.ContentProviderClient.java
org.devtcg.sqliteserver.impl.binder.SQLiteServerProtocolException.java
org.devtcg.sqliteserver.impl.binder.ServerImpl.java
org.devtcg.sqliteserver.impl.binder.ServerState.java
org.devtcg.sqliteserver.impl.binder.ServiceClient.java
org.devtcg.sqliteserver.impl.binder.ThreadAffinityExecutor.java
org.devtcg.sqliteserver.impl.binder.protocol.AbstractCommandHandler.java
org.devtcg.sqliteserver.impl.binder.protocol.AbstractCommandMessage.java
org.devtcg.sqliteserver.impl.binder.protocol.AcquireCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.BeginTransactionCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.DeleteCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.EndTransactionCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.ExceptionTransportHelper.java
org.devtcg.sqliteserver.impl.binder.protocol.ExecSQLCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.InsertCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.MethodName.java
org.devtcg.sqliteserver.impl.binder.protocol.RawQueryCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.ReleaseCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.SetTransactionSuccessfulCommand.java
org.devtcg.sqliteserver.impl.binder.protocol.UpdateCommand.java
org.devtcg.sqliteserver.sample.MyActivity.java
org.devtcg.sqliteserver.sample.MyOpenHelper.java
org.devtcg.sqliteserver.sample.TestContentProvider.java
org.devtcg.sqliteserver.sample.TestService.java