PageRenderTime 33ms CodeModel.GetById 14ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/WebVox/src/com/marvin/webvox/ScriptDatabase.java

http://eyes-free.googlecode.com/
Java | 259 lines | 155 code | 55 blank | 49 comment | 19 complexity | 50298f2d38d9b823c97f39baa5669a2e 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.marvin.webvox;
 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.mgws));
 73		  this.insertScript(db, Util.getRawString(res, R.raw.mgmail));
 74		  this.insertScript(db, Util.getRawString(res, R.raw.basic));
 75			//this.insertScript(db, Util.getRawString(res, R.raw.email));
 76			//this.insertScript(db, Util.getRawString(res, R.raw.halfscan));
 77			//this.insertScript(db, Util.getRawString(res, R.raw.sharedigg));
 78			//this.insertScript(db, Util.getRawString(res, R.raw.wikipedia));
 79			//this.insertScript(db, Util.getRawString(res, R.raw.slashdot));
 80			//this.insertScript(db, Util.getRawString(res, R.raw.userscripts));
 81		} catch(Exception e) {
 82			Log.e(TAG, "Problem while inserting default scripts", e);
 83		}
 84		
 85		
 86	}
 87
 88	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 89		int currentVersion = oldVersion;
 90		
 91		if(currentVersion != newVersion) {
 92			db.execSQL("DROP TABLE IF EXISTS " + TABLE_SCRIPTS);
 93			onCreate(db);	
 94		}
 95	}
 96	
 97	public static Pattern headerRegex = Pattern.compile("^// @([^\\s]+)\\s+(.+?)$", Pattern.MULTILINE);
 98	public final static String UNKNOWN = "Unknown";
 99	
100	/**
101	 * Format a domain "include" statement so it behaves nicely as a Java regex.
102	 */
103	public static String formatDomain(String domain) {
104		
105		// escape any "." and replace "*" with generic matcher
106		domain = domain.replace(".", "\\.");
107		domain = domain.replace("*", ".*");
108		return domain;
109		
110	}
111	
112	/**
113	 * Import the given script into our database.
114	 * @throws Exception if problem parsing script 
115	 */
116	public long insertScript(SQLiteDatabase db, String raw) throws Exception {
117		if(db == null) db = this.getWritableDatabase();
118		
119		// extract metadata from script comments
120		String name = UNKNOWN, author = UNKNOWN, descrip = UNKNOWN;
121		StringBuilder include = new StringBuilder();
122		include.append('(');
123		
124		try {
125			Matcher matcher = headerRegex.matcher(raw);
126			while(matcher.find()) {
127				String key = matcher.group(1),
128					value = matcher.group(2);
129				
130				Log.d(TAG, String.format("found header %s=%s", key, value));
131
132				if("name".equals(key)) {
133					name = value;
134				} else if("author".equals(key)) {
135					author = value;
136				} else if("description".equals(key)) {
137					descrip = value;
138				} else if("include".equals(key)) {
139					include.append(formatDomain(value));
140					include.append('|');
141				}
142			}
143		} catch(Exception e) {
144			Log.e(TAG, "Problem while parsing script header", e);
145		}
146		
147		String domainregex = "";
148		if(include.length() > 0) {
149			// replace last '|' with a closing bracket
150			include.setCharAt(include.length() - 1, ')');
151			domainregex = include.toString();
152		}
153		
154		// script is valid if has name and parsable domain regex
155		if(UNKNOWN.equals(name))
156			throw new Exception("No name found in script");
157		
158		try {
159			Pattern.compile(domainregex);
160		} catch(Exception e) {
161			throw new Exception("Problem parsing domain regex", e);
162		}
163		
164		//Log.d(TAG, String.format("domainregex=%s", domainregex));
165
166		ContentValues values = new ContentValues();
167		values.put(FIELD_SCRIPT_NAME, name);
168		values.put(FIELD_SCRIPT_AUTHOR, author);
169		values.put(FIELD_SCRIPT_DESCRIP, descrip);
170		values.put(FIELD_SCRIPT_DOMAINREGEX, domainregex);
171		values.put(FIELD_SCRIPT_CONTENT, raw);
172		values.put(FIELD_SCRIPT_ENABLED, 1);
173	
174		return db.insert(TABLE_SCRIPTS, null, values);
175		
176	}
177	
178	/**
179	 * Return cursor across all scripts.
180	 */
181	public Cursor getScripts() {
182		SQLiteDatabase db = this.getReadableDatabase();
183		return db.query(TABLE_SCRIPTS, new String[] { "_id", FIELD_SCRIPT_NAME,
184				FIELD_SCRIPT_AUTHOR, FIELD_SCRIPT_DESCRIP, FIELD_SCRIPT_DOMAINREGEX,
185				FIELD_SCRIPT_ENABLED }, null, null, null, null, null);
186		
187	}
188	
189	/**
190	 * Delete a specific script.
191	 */
192	public void deleteScript(long id) {
193		SQLiteDatabase db = this.getWritableDatabase();		
194		db.delete(TABLE_SCRIPTS, "_id = ?", new String[] { Long.toString(id) });
195		
196	}
197	
198	/**
199	 * Toggle the enabled state of the given script.
200	 */
201	public void toggleEnabled(long id) {
202		SQLiteDatabase db = this.getWritableDatabase();
203		
204		// first read the existing status
205		Cursor cur = db.query(TABLE_SCRIPTS, new String[] { FIELD_SCRIPT_ENABLED }, "_id = ?", new String[] { Long.toString(id) }, null, null, null);
206		if(cur == null || !cur.moveToFirst()) return;
207		int value = cur.getInt(cur.getColumnIndex(FIELD_SCRIPT_ENABLED));
208		cur.close();
209
210		// update to have the opposite value
211		ContentValues values = new ContentValues();
212		values.put(FIELD_SCRIPT_ENABLED, (value == 0) ? 1 : 0);
213		db.update(TABLE_SCRIPTS, values, "_id = ?", new String[] { Long.toString(id) });
214		
215	}
216	
217	private Map<Pattern,String> cache = new HashMap<Pattern,String>();
218	
219	private void validateCache() {
220		
221		SQLiteDatabase db = this.getReadableDatabase();
222		Cursor cur = db.query(TABLE_SCRIPTS, new String[] { FIELD_SCRIPT_DOMAINREGEX,
223				FIELD_SCRIPT_CONTENT }, FIELD_SCRIPT_ENABLED + " = 1", null, null, null, null);
224		
225		int COL_DOMAINREGEX = cur.getColumnIndex(FIELD_SCRIPT_DOMAINREGEX),
226			COL_CONTENT = cur.getColumnIndex(FIELD_SCRIPT_CONTENT);
227		
228		cache.clear();
229		
230		while(cur.moveToNext()) {
231			String domainregex = cur.getString(COL_DOMAINREGEX),
232				content = cur.getString(COL_CONTENT);
233			cache.put(Pattern.compile(domainregex), content);
234			
235		}
236		
237		cur.close();
238		
239	}
240
241	/**
242	 * Return Javascript (CONTENT) for all scripts that should be active given
243	 * this specific url.
244	 */
245	public List<String> getActive(String url) {
246		List<String> active = new LinkedList<String>();
247		
248		this.validateCache();
249		for(Pattern trial : cache.keySet()) {
250			if(trial.matcher(url).matches())
251				active.add(cache.get(trial));
252		}
253		
254		return active;
255	}
256	
257	
258
259}