/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package getfacts;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.tmatesoft.sqljet.core.SqlJetException;
import org.tmatesoft.sqljet.core.SqlJetTransactionMode;
import org.tmatesoft.sqljet.core.schema.SqlJetConflictAction;
import org.tmatesoft.sqljet.core.table.ISqlJetCursor;
import org.tmatesoft.sqljet.core.table.ISqlJetTable;
import org.tmatesoft.sqljet.core.table.SqlJetDb;
/**
*
* @author jmc15
*/
public class NewsSafe
{
private static final Object _lock_ = new ArrayList();
public static File getBaseDir()
{
String homeDir = System.getProperty("user.home");
File gfDir = new File(homeDir, ".getfacts");
if( gfDir.exists()==false )
{
if( gfDir.mkdir() == false )
{
return null;
}
}
return gfDir;
}
private static File getNewsSafePath()
{
File gfDir = getBaseDir();
return new File(gfDir, "news.db");
}
private static boolean CreateDatabaseIfNotExists(SqlJetDb db)
throws SqlJetException
{
db.beginTransaction(SqlJetTransactionMode.WRITE);
try
{
// Create table for the FrontPages
StringBuilder fpStmt = new StringBuilder();
fpStmt.append("CREATE TABLE IF NOT EXISTS front_pages (");
fpStmt.append("key TEXT NOT NULL PRIMARY KEY, ");
fpStmt.append("title TEXT NOT NULL");
fpStmt.append(")");
db.createTable(fpStmt.toString());
// Create table for articles
StringBuilder aStmt = new StringBuilder();
aStmt.append("CREATE TABLE IF NOT EXISTS articles (");
aStmt.append("key TEXT NOT NULL PRIMARY KEY, ");
aStmt.append("front_page TEXT NOT NULL, ");
aStmt.append("title TEXT NOT NULL, ");
aStmt.append("content TEXT, ");
aStmt.append("url TEXT, ");
aStmt.append("image TEXT, ");
aStmt.append("published INTEGER, ");
aStmt.append("refreshed INTEGER, ");
aStmt.append("new_entry TEXT");
aStmt.append(")");
db.createTable(aStmt.toString());
// create index to sort articles by
// publication date
StringBuilder pIdxStmt = new StringBuilder();
pIdxStmt.append("CREATE INDEX IF NOT EXISTS published_article_index ON articles(front_page)");
db.createIndex(pIdxStmt.toString());
//db.getOptions().setUserVersion(1);
db.commit();
return true;
}
catch(Exception ex)
{
Logger.getLogger(NewsSafe.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
finally
{
db.rollback();
}
}
private static boolean CreateOrUpdateFrontPage(SqlJetDb db, FrontPage fp)
throws SqlJetException
{
db.beginTransaction(SqlJetTransactionMode.WRITE);
try
{
ISqlJetTable table = db.getTable("front_pages");
Map<String,Object> fields = new HashMap<String, Object>();
fields.put("key", fp.getUserTitle() );
fields.put("title", fp.getTitle() );
long rowid = table.insertByFieldNamesOr(SqlJetConflictAction.REPLACE, fields);
db.commit();
return true;
}
catch(Exception ex)
{
Logger.getLogger(NewsSafe.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
finally
{
db.rollback();
}
}
private static boolean CreateOrUpdateArticle(SqlJetDb db, FrontPage fp, Article a, boolean insertOnly)
throws SqlJetException
{
db.beginTransaction(SqlJetTransactionMode.WRITE);
try
{
ISqlJetTable table = db.getTable("articles");
Map<String,Object> fields = new HashMap<String, Object>();
fields.put("key", a.getGuid() );
fields.put("front_page", fp.getUserTitle() );
fields.put("title", a.getTitle() );
fields.put("content", a.getContent() );
fields.put("url", a.getUrl());
File imageFile = a .getImageFile();
if(imageFile!=null)
{
fields.put("image", imageFile.getName() );
}
else
{
fields.put("image", null);
}
fields.put("published", a.getPublicationDate() );
fields.put("refreshed", Calendar.getInstance().getTimeInMillis() );
long rowid;
if( insertOnly==true )
{
fields.put("new_entry", Boolean.TRUE.toString());
rowid = table.insertByFieldNames(fields);
}
else
{
fields.put("new_entry", Boolean.FALSE.toString());
rowid = table.insertByFieldNamesOr(SqlJetConflictAction.REPLACE, fields);
}
db.commit();
return true;
}
catch(Exception ex)
{
//Logger.getLogger(NewsSafe.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
finally
{
db.rollback();
}
}
public static void storeNews(FrontPage fp)
{
synchronized(_lock_)
{
try
{
// open the user's storage area
File dbFile = getNewsSafePath();
SqlJetDb db = SqlJetDb.open(dbFile, true);
try
{
CreateDatabaseIfNotExists(db);
CreateOrUpdateFrontPage(db, fp);
for(int i=0; i<fp.getArticlesCount(); i++)
{
if( CreateOrUpdateArticle(db, fp, fp.getArticle(i), true) == false )
{
CreateOrUpdateArticle(db, fp, fp.getArticle(i), false);
}
}
}
finally
{
db.close();
}
}
catch (SqlJetException ex)
{
Logger.getLogger(NewsSafe.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private static BasicFrontPage getFrontPage(SqlJetDb db, String frontPageName)
throws SqlJetException
{
BasicFrontPage fp = new BasicFrontPage();
ISqlJetTable table = db.getTable("front_pages");
ISqlJetCursor cursor = table.lookup(null, frontPageName);
try
{
fp.setUserTitle( cursor.getString("key") );
fp.frontPageTitle = cursor.getString("title");
return fp;
}
finally
{
cursor.close();
}
}
private static BasicArticle getArticle(ISqlJetCursor cursor)
throws SqlJetException, IOException
{
BasicArticle article = new BasicArticle();
article.content = cursor.getString("content");
article.guid = cursor.getString("key");
article.pubDate = cursor.getInteger("published");
article.title = cursor.getString("title");
article.url = cursor.getString("url");
String imageFileName = cursor.getString("image");
if( imageFileName != null)
{
File gfDir = getBaseDir();
article.imageFile = new File(gfDir, imageFileName);
}
else
{
article.imageFile=null;
}
article.isNew = Boolean.parseBoolean( cursor.getString("new_entry") );
/*aStmt.append("key TEXT NOT NULL PRIMARY KEY, ");
aStmt.append("front_page TEXT NOT NULL, ");
aStmt.append("title TEXT NOT NULL, ");
aStmt.append("content TEXT, ");
aStmt.append("url TEXT, ");
aStmt.append("image BLOB, ");
aStmt.append("published INTEGER");*/
return article;
}
/**
* Returns one front page containing up to 'count' articles.
* The articles have been ordered from freshest to oldest,
* based on their date of publication.
* @param index first index is 1.
* @param count
* @return
*/
public static FrontPage getTheFrontPage(int index, int count)
{
synchronized(_lock_)
{
try
{
// open the user's storage area
File dbFile = getNewsSafePath();
SqlJetDb db = SqlJetDb.open(dbFile, false);
try
{
db.beginTransaction(SqlJetTransactionMode.READ_ONLY);
try
{
ISqlJetTable table = db.getTable("articles");
ISqlJetCursor cursor = table.order("published_article_index"/*table.getPrimaryKeyIndexName()*/);
long rowCount = cursor.getRowCount();
try
{
if( cursor.goToRow(index) == false )
{
return null;
}
// the front page name of this first article
// will be memorized, because all the following
// articles will have to match the same.
String frontPageName = cursor.getString("front_page");
// build the front page from database:
BasicFrontPage fp = getFrontPage(db, frontPageName);
do
{
if( frontPageName.compareTo( cursor.getString("front_page"))!=0)
{
break;
}
// build article from the cursor's current
// position:
try
{
Article a = getArticle(cursor);
fp.articles.add(a);
}
catch (IOException ex)
{
Logger.getLogger(NewsSafe.class.getName()).log(Level.SEVERE, null, ex);
break;
}
if( cursor.next() == false )
{
break;
}
}while( fp.articles.size()<count);
return fp;
}
finally
{
cursor.close();
}
}
finally
{
db.rollback();
}
}
finally
{
db.close();
}
}
catch (SqlJetException ex)
{
Logger.getLogger(NewsSafe.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
static void gb(FetcherObserver observer)
{
synchronized(_lock_)
{
System.out.println("Collecting garbage...");
long currentDateTimeInMillis = Calendar.getInstance().getTimeInMillis();
int deletedArticlesCount = 0;
int deletedImagesCount = 0;
//- - - - - - - - - - - - - - -
// retrieve all ".dat" files
// in the user's directory
//- - - - - - - - - - - - - - -
File gfPath = getBaseDir();
String[] filesArray = gfPath.list( new FilenameFilter() {
public boolean accept(File file, String string) {
return string.endsWith(".dat");
}
});
ArrayList<String> filesList = new ArrayList(Arrays.asList(filesArray));
//- - - - - - - - - - - - - - -
// open the user's data base
//- - - - - - - - - - - - - - -
File dbFile = getNewsSafePath();
try
{
SqlJetDb db = SqlJetDb.open(dbFile, true);
try
{
db.beginTransaction(SqlJetTransactionMode.WRITE);
try
{
ISqlJetTable table = db.getTable("articles");
ISqlJetCursor cursor = table.open();
try
{
//- - - - - - - - - - - - - - -
// For each entry in the
// "articles" table...
//- - - - - - - - - - - - - - -
do
{
// Remove the article if it has not
// been refreshed for too long
long refreshDateInMillis = cursor.getInteger("refreshed");
long diffTime = Math.abs(currentDateTimeInMillis - refreshDateInMillis);
if( diffTime > (1000*60*60) ) // not refreshed during the last 60 minutes
{
String entry = String.format("\tDelete old article \"%s (%s)\" \r\n",
cursor.getString("title"),
cursor.getString("front_page"));
System.out.println(entry);
cursor.delete();
}
else
{
// Remove registered image from the list
// of ".dat" files to erase from disk
String imageFileName = cursor.getString("image");
filesList.remove(imageFileName);
}
}while( cursor.next() == true);
db.commit();
}
finally
{
cursor.close();
}
for(String imageFileName : filesList )
{
System.out.format("\tDelete unused file %s\r\n", imageFileName);
File imageFile = new File(gfPath, imageFileName);
imageFile.delete();
}
}
catch(Exception ex)
{
db.rollback();
}
}
finally
{
db.close();
}
}
catch (Exception ex)
{
Logger.getLogger(NewsSafe.class.getName()).log(Level.SEVERE, null, ex);
}
if( observer != null )
{
observer.signal( String.format("%d old article%s and %d old image%s removed",
deletedArticlesCount,
deletedArticlesCount > 1 ?"s":"",
deletedImagesCount,
deletedImagesCount > 1 ?"s":"") );
}
System.out.println("Garbage collection done.");
}
}
}