PageRenderTime 25ms CodeModel.GetById 2ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 1ms

/CVox/src/com/cvox/browser/ScriptDatabase.java

http://eyes-free.googlecode.com/
Java | 258 lines | 154 code | 55 blank | 49 comment | 19 complexity | 4e059e6bce1b386a63a60763b967e373 MD5 | raw file
  1/*
  2 * Copyright (C) 2008 Google Inc.
  3 * 
  4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5 * use this file except in compliance with the License. You may obtain a copy of
  6 * the License at
  7 * 
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 * 
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 13 * License for the specific language governing permissions and limitations under
 14 * the License.
 15 */
 16
 17package com.cvox.browser;
 18
 19import java.io.InputStream;
 20import java.util.HashMap;
 21import java.util.LinkedList;
 22import java.util.List;
 23import java.util.Map;
 24import java.util.regex.Matcher;
 25import java.util.regex.Pattern;
 26
 27import org.json.JSONArray;
 28import org.json.JSONObject;
 29
 30import android.content.ContentValues;
 31import android.content.Context;
 32import android.content.res.Resources;
 33import android.database.Cursor;
 34import android.database.sqlite.SQLiteDatabase;
 35import android.database.sqlite.SQLiteOpenHelper;
 36import android.util.Log;
 37
 38public class ScriptDatabase extends SQLiteOpenHelper {
 39	
 40	public final static String TAG = ScriptDatabase.class.toString();
 41	
 42	public final static String DB_NAME = "scripts";
 43	public final static int DB_VERSION = 3;
 44	
 45	public final static String TABLE_SCRIPTS = "scripts";
 46	public final static String FIELD_SCRIPT_NAME = "title";
 47	public final static String FIELD_SCRIPT_AUTHOR = "author";
 48	public final static String FIELD_SCRIPT_DESCRIP = "descrip";
 49	public final static String FIELD_SCRIPT_DOMAINREGEX = "domain";
 50	public final static String FIELD_SCRIPT_CONTENT = "content";
 51	public final static String FIELD_SCRIPT_ENABLED = "enabled";
 52	
 53	private final Resources res;
 54
 55	public ScriptDatabase(Context context) {
 56		super(context, DB_NAME, null, DB_VERSION);
 57		this.res = context.getResources();
 58	}
 59
 60	public void onCreate(SQLiteDatabase db) {
 61		db.execSQL("CREATE TABLE " + TABLE_SCRIPTS
 62				+ " (_id INTEGER PRIMARY KEY, "
 63				+ FIELD_SCRIPT_NAME + " TEXT, "
 64				+ FIELD_SCRIPT_AUTHOR + " TEXT, "
 65				+ FIELD_SCRIPT_DESCRIP + " TEXT, "
 66				+ FIELD_SCRIPT_DOMAINREGEX + " TEXT, "
 67				+ FIELD_SCRIPT_CONTENT + " TEXT, "
 68				+ FIELD_SCRIPT_ENABLED + " INTEGER)");
 69
 70		// populate database with a few example scripts 
 71		try {
 72		  this.insertScript(db, Util.getRawString(res, R.raw.gws));
 73		  this.insertScript(db, Util.getRawString(res, R.raw.basic));
 74			//this.insertScript(db, Util.getRawString(res, R.raw.email));
 75			//this.insertScript(db, Util.getRawString(res, R.raw.halfscan));
 76			//this.insertScript(db, Util.getRawString(res, R.raw.sharedigg));
 77			//this.insertScript(db, Util.getRawString(res, R.raw.wikipedia));
 78			//this.insertScript(db, Util.getRawString(res, R.raw.slashdot));
 79			//this.insertScript(db, Util.getRawString(res, R.raw.userscripts));
 80		} catch(Exception e) {
 81			Log.e(TAG, "Problem while inserting default scripts", e);
 82		}
 83		
 84		
 85	}
 86
 87	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 88		int currentVersion = oldVersion;
 89		
 90		if(currentVersion != newVersion) {
 91			db.execSQL("DROP TABLE IF EXISTS " + TABLE_SCRIPTS);
 92			onCreate(db);	
 93		}
 94	}
 95	
 96	public static Pattern headerRegex = Pattern.compile("^// @([^\\s]+)\\s+(.+?)$", Pattern.MULTILINE);
 97	public final static String UNKNOWN = "Unknown";
 98	
 99	/**
100	 * Format a domain "include" statement so it behaves nicely as a Java regex.
101	 */
102	public static String formatDomain(String domain) {
103		
104		// escape any "." and replace "*" with generic matcher
105		domain = domain.replace(".", "\\.");
106		domain = domain.replace("*", ".*");
107		return domain;
108		
109	}
110	
111	/**
112	 * Import the given script into our database.
113	 * @throws Exception if problem parsing script 
114	 */
115	public long insertScript(SQLiteDatabase db, String raw) throws Exception {
116		if(db == null) db = this.getWritableDatabase();
117		
118		// extract metadata from script comments
119		String name = UNKNOWN, author = UNKNOWN, descrip = UNKNOWN;
120		StringBuilder include = new StringBuilder();
121		include.append('(');
122		
123		try {
124			Matcher matcher = headerRegex.matcher(raw);
125			while(matcher.find()) {
126				String key = matcher.group(1),
127					value = matcher.group(2);
128				
129				Log.d(TAG, String.format("found header %s=%s", key, value));
130
131				if("name".equals(key)) {
132					name = value;
133				} else if("author".equals(key)) {
134					author = value;
135				} else if("description".equals(key)) {
136					descrip = value;
137				} else if("include".equals(key)) {
138					include.append(formatDomain(value));
139					include.append('|');
140				}
141			}
142		} catch(Exception e) {
143			Log.e(TAG, "Problem while parsing script header", e);
144		}
145		
146		String domainregex = "";
147		if(include.length() > 0) {
148			// replace last '|' with a closing bracket
149			include.setCharAt(include.length() - 1, ')');
150			domainregex = include.toString();
151		}
152		
153		// script is valid if has name and parsable domain regex
154		if(UNKNOWN.equals(name))
155			throw new Exception("No name found in script");
156		
157		try {
158			Pattern.compile(domainregex);
159		} catch(Exception e) {
160			throw new Exception("Problem parsing domain regex", e);
161		}
162		
163		//Log.d(TAG, String.format("domainregex=%s", domainregex));
164
165		ContentValues values = new ContentValues();
166		values.put(FIELD_SCRIPT_NAME, name);
167		values.put(FIELD_SCRIPT_AUTHOR, author);
168		values.put(FIELD_SCRIPT_DESCRIP, descrip);
169		values.put(FIELD_SCRIPT_DOMAINREGEX, domainregex);
170		values.put(FIELD_SCRIPT_CONTENT, raw);
171		values.put(FIELD_SCRIPT_ENABLED, 1);
172	
173		return db.insert(TABLE_SCRIPTS, null, values);
174		
175	}
176	
177	/**
178	 * Return cursor across all scripts.
179	 */
180	public Cursor getScripts() {
181		SQLiteDatabase db = this.getReadableDatabase();
182		return db.query(TABLE_SCRIPTS, new String[] { "_id", FIELD_SCRIPT_NAME,
183				FIELD_SCRIPT_AUTHOR, FIELD_SCRIPT_DESCRIP, FIELD_SCRIPT_DOMAINREGEX,
184				FIELD_SCRIPT_ENABLED }, null, null, null, null, null);
185		
186	}
187	
188	/**
189	 * Delete a specific script.
190	 */
191	public void deleteScript(long id) {
192		SQLiteDatabase db = this.getWritableDatabase();		
193		db.delete(TABLE_SCRIPTS, "_id = ?", new String[] { Long.toString(id) });
194		
195	}
196	
197	/**
198	 * Toggle the enabled state of the given script.
199	 */
200	public void toggleEnabled(long id) {
201		SQLiteDatabase db = this.getWritableDatabase();
202		
203		// first read the existing status
204		Cursor cur = db.query(TABLE_SCRIPTS, new String[] { FIELD_SCRIPT_ENABLED }, "_id = ?", new String[] { Long.toString(id) }, null, null, null);
205		if(cur == null || !cur.moveToFirst()) return;
206		int value = cur.getInt(cur.getColumnIndex(FIELD_SCRIPT_ENABLED));
207		cur.close();
208
209		// update to have the opposite value
210		ContentValues values = new ContentValues();
211		values.put(FIELD_SCRIPT_ENABLED, (value == 0) ? 1 : 0);
212		db.update(TABLE_SCRIPTS, values, "_id = ?", new String[] { Long.toString(id) });
213		
214	}
215	
216	private Map<Pattern,String> cache = new HashMap<Pattern,String>();
217	
218	private void validateCache() {
219		
220		SQLiteDatabase db = this.getReadableDatabase();
221		Cursor cur = db.query(TABLE_SCRIPTS, new String[] { FIELD_SCRIPT_DOMAINREGEX,
222				FIELD_SCRIPT_CONTENT }, FIELD_SCRIPT_ENABLED + " = 1", null, null, null, null);
223		
224		int COL_DOMAINREGEX = cur.getColumnIndex(FIELD_SCRIPT_DOMAINREGEX),
225			COL_CONTENT = cur.getColumnIndex(FIELD_SCRIPT_CONTENT);
226		
227		cache.clear();
228		
229		while(cur.moveToNext()) {
230			String domainregex = cur.getString(COL_DOMAINREGEX),
231				content = cur.getString(COL_CONTENT);
232			cache.put(Pattern.compile(domainregex), content);
233			
234		}
235		
236		cur.close();
237		
238	}
239
240	/**
241	 * Return Javascript (CONTENT) for all scripts that should be active given
242	 * this specific url.
243	 */
244	public List<String> getActive(String url) {
245		List<String> active = new LinkedList<String>();
246		
247		this.validateCache();
248		for(Pattern trial : cache.keySet()) {
249			if(trial.matcher(url).matches())
250				active.add(cache.get(trial));
251		}
252		
253		return active;
254	}
255	
256	
257
258}