/* * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Codename One designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Codename One through http://www.codenameone.com/ if you * need additional information or have any questions. */ package com.codename1.db; import com.codename1.io.Log; import com.codename1.util.EasyThread; import com.codename1.util.RunnableWithResult; import com.codename1.util.RunnableWithResultSync; import com.codename1.util.SuccessCallback; import java.io.IOException; /** * Wraps all database calls in a single thread so they are all proxied thru that thread * * @author Shai Almog */ public class ThreadSafeDatabase extends Database { private Database underlying; private EasyThread et; /** * Wraps the given database with a threadsafe version * @param db the database */ public ThreadSafeDatabase(Database db) { underlying = db; } /** * Returns the underlying easy thread we can use to pipe tasks to the db thread * @return the easy thread object */ public EasyThread getThread() { return et; } @Override public void beginTransaction() throws IOException { invokeWithException(new RunnableWithIOException() { public void run() throws IOException { underlying.beginTransaction(); } }); } interface RunnableWithIOException { public void run() throws IOException; } interface RunnableWithResponseOrIOException { public Object run() throws IOException; } private void invokeWithException(final RunnableWithIOException r) throws IOException { IOException err = et.run(new RunnableWithResultSync<IOException>() { public IOException run() { try { r.run(); return null; } catch(IOException err) { return err; } } }); if(err != null) { throw err; } } private Object invokeWithException(final RunnableWithResponseOrIOException r) throws IOException { Object ret = et.run(new RunnableWithResultSync<Object>() { public Object run() { try { return r.run(); } catch(IOException err) { return err; } } }); if(ret instanceof IOException) { throw (IOException)ret; } return ret; } @Override public void commitTransaction() throws IOException { invokeWithException(new RunnableWithIOException() { public void run() throws IOException { underlying.beginTransaction(); } }); } @Override public void rollbackTransaction() throws IOException { invokeWithException(new RunnableWithIOException() { public void run() throws IOException { underlying.rollbackTransaction(); } }); } @Override public void close() { // close should NEVER throw an exception... et.run(new Runnable() { public void run() { try { underlying.close(); } catch(IOException err) { Log.e(err); } } }); } @Override public void execute(final String sql) throws IOException { invokeWithException(new RunnableWithIOException() { public void run() throws IOException { underlying.execute(sql); } }); } @Override public void execute(final String sql, final String[] params) throws IOException { invokeWithException(new RunnableWithIOException() { public void run() throws IOException { underlying.execute(sql, params); } }); } private class RowWrapper implements Row { private Row underlyingRow; public RowWrapper(Row underlyingRow) { this.underlyingRow = underlyingRow; } public byte[] getBlob(final int index) throws IOException { return (byte[])invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingRow.getBlob(index); } }); } public double getDouble(final int index) throws IOException { return (Double)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingRow.getDouble(index); } }); } public float getFloat(final int index) throws IOException { return (Float)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingRow.getFloat(index); } }); } public int getInteger(final int index) throws IOException { return (Integer)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingRow.getInteger(index); } }); } public long getLong(final int index) throws IOException { return (Long)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingRow.getLong(index); } }); } public short getShort(final int index) throws IOException { return (Short)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingRow.getShort(index); } }); } public String getString(final int index) throws IOException { return (String)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingRow.getString(index); } }); } } private class CursorWrapper implements Cursor { private Cursor underlyingCursor; public CursorWrapper(Cursor underlyingCursor) { this.underlyingCursor = underlyingCursor; } public boolean first() throws IOException { return (Boolean)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.first(); } }); } public boolean last() throws IOException { return (Boolean)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.last(); } }); } public boolean next() throws IOException { return (Boolean)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.next(); } }); } public boolean prev() throws IOException { return (Boolean)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.prev(); } }); } public int getColumnIndex(final String columnName) throws IOException { return (Integer)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.getColumnIndex(columnName); } }); } public String getColumnName(final int columnIndex) throws IOException { return (String)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.getColumnName(columnIndex); } }); } public int getColumnCount() throws IOException { return (Integer)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.getColumnCount(); } }); } public int getPosition() throws IOException { return (Integer)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.getPosition(); } }); } public boolean position(final int row) throws IOException { return (Boolean)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.position(row); } }); } public void close() throws IOException { invokeWithException(new RunnableWithIOException() { public void run() throws IOException { underlyingCursor.close(); } }); } public Row getRow() throws IOException { return new RowWrapper((Row)invokeWithException(new RunnableWithResponseOrIOException() { public Object run() throws IOException { return underlyingCursor.getRow(); } })); } } @Override public Cursor executeQuery(final String sql, final String[] params) throws IOException { final Cursor[] curs = new Cursor[1]; invokeWithException(new RunnableWithIOException() { public void run() throws IOException { curs[0] = underlying.executeQuery(sql, params); } }); return new CursorWrapper(curs[0]); } @Override public Cursor executeQuery(final String sql) throws IOException { final Cursor[] curs = new Cursor[1]; invokeWithException(new RunnableWithIOException() { public void run() throws IOException { curs[0] = underlying.executeQuery(sql); } }); return new CursorWrapper(curs[0]); } @Override public Cursor executeQuery(final String sql, final Object... params) throws IOException { final Cursor[] curs = new Cursor[1]; invokeWithException(new RunnableWithIOException() { public void run() throws IOException { curs[0] = underlying.executeQuery(sql, params); } }); return new CursorWrapper(curs[0]); } @Override public void execute(final String sql, final Object... params) throws IOException { invokeWithException(new RunnableWithIOException() { public void run() throws IOException { underlying.execute(sql, params); } }); } }