more updates to the new bookmarks (ymarks)....

- split YMarkTables and YMarkIndex in two different classes
- HTML import is working properly
- XBEL import is still broken


git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@7292 6c8d7289-2bf4-0310-a012-ef5d649a1542
pull/1/head
apfelmaennchen 15 years ago
parent 445619f3ec
commit f5324b27f2

@ -1,11 +1,7 @@
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.HashMap;
import net.yacy.cora.protocol.RequestHeader;
import net.yacy.kelondro.blob.Tables;
import net.yacy.kelondro.blob.Tables.Data;
import net.yacy.kelondro.index.RowSpaceExceededException;
import net.yacy.kelondro.logging.Log;
import de.anomic.data.YMarkTables;
@ -17,10 +13,8 @@ import de.anomic.server.serverSwitch;
public class add_ymark {
private static Switchboard sb = null;
public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) {
sb = (Switchboard) env;
final Switchboard sb = (Switchboard) env;
final serverObjects prop = new serverObjects();
final userDB.Entry user = sb.userDB.getUser(header);
@ -28,106 +22,32 @@ public class add_ymark {
final boolean isAuthUser = user!= null && user.hasRight(userDB.Entry.BOOKMARK_RIGHT);
if(isAdmin || isAuthUser) {
final String bmk_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.BOOKMARKS.basename();
final String tag_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.TAGS.basename();
final String folder_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.FOLDERS.basename();
byte[] urlHash = null;
String url ="";
if(post.containsKey(YMarkTables.BOOKMARK.URL.key())) {
try {
url = post.get(YMarkTables.BOOKMARK.URL.key(),YMarkTables.BOOKMARK.URL.deflt());
boolean hasProtocol = false;
for (YMarkTables.PROTOCOLS p : YMarkTables.PROTOCOLS.values()) {
hasProtocol = url.toLowerCase().startsWith(p.protocol());
}
if (!hasProtocol) {
url=YMarkTables.PROTOCOLS.HTTP.protocol(url);
}
urlHash = YMarkTables.getBookmarkId(url);
} catch (MalformedURLException e) {
Log.logException(e);
}
} else if (post.containsKey(YMarkTables.BOOKMARKS_ID)) {
urlHash = post.get(YMarkTables.BOOKMARKS_ID).getBytes();
}
if(urlHash == null) {
prop.put("result", "0");
return prop;
}
final String bmk_user = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN);
// read old entry from the bookmarks table (if exists)
Tables.Row bmk_row = null;
try {
bmk_row = sb.tables.select(bmk_table, urlHash);
} catch (IOException e) {
Log.logException(e);
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
String url = post.get(YMarkTables.BOOKMARK.URL.key(),YMarkTables.BOOKMARK.URL.deflt());
boolean hasProtocol = false;
for (YMarkTables.PROTOCOLS p : YMarkTables.PROTOCOLS.values()) {
hasProtocol = url.toLowerCase().startsWith(p.protocol());
}
if (!hasProtocol) {
url=YMarkTables.PROTOCOLS.HTTP.protocol(url);
}
final HashMap<String,String> data = new HashMap<String,String>();
data.put(YMarkTables.BOOKMARK.URL.key(), url);
data.put(YMarkTables.BOOKMARK.TITLE.key(), post.get(YMarkTables.BOOKMARK.TITLE.key(),YMarkTables.BOOKMARK.TITLE.deflt()));
data.put(YMarkTables.BOOKMARK.DESC.key(), post.get(YMarkTables.BOOKMARK.DESC.key(),YMarkTables.BOOKMARK.DESC.deflt()));
data.put(YMarkTables.BOOKMARK.PUBLIC.key(), post.get(YMarkTables.BOOKMARK.PUBLIC.key(),YMarkTables.BOOKMARK.PUBLIC.deflt()));
data.put(YMarkTables.BOOKMARK.TAGS.key(), YMarkTables.cleanTagsString(post.get(YMarkTables.BOOKMARK.TAGS.key(),YMarkTables.BOOKMARK.TAGS.deflt())));
data.put(YMarkTables.BOOKMARK.FOLDERS.key(), YMarkTables.cleanFoldersString(post.get(YMarkTables.BOOKMARK.FOLDERS.key(),YMarkTables.FOLDERS_UNSORTED)));
// insert or update entry
final byte[] date = String.valueOf(System.currentTimeMillis()).getBytes();
try {
if (bmk_row == null) {
// create and insert new entry
Data data = new Data();
final String tagsString = YMarkTables.cleanTagsString(post.get(YMarkTables.BOOKMARK.TAGS.key(),YMarkTables.BOOKMARK.TAGS.deflt()));
final String foldersString = YMarkTables.cleanFoldersString(post.get(YMarkTables.BOOKMARK.FOLDERS.key(),YMarkTables.FOLDERS_UNSORTED));
data.put(YMarkTables.BOOKMARK.URL.key(), url.getBytes());
data.put(YMarkTables.BOOKMARK.TITLE.key(), post.get(YMarkTables.BOOKMARK.TITLE.key(),YMarkTables.BOOKMARK.TITLE.deflt()));
data.put(YMarkTables.BOOKMARK.DESC.key(), post.get(YMarkTables.BOOKMARK.DESC.key(),YMarkTables.BOOKMARK.DESC.deflt()));
data.put(YMarkTables.BOOKMARK.PUBLIC.key(), post.get(YMarkTables.BOOKMARK.PUBLIC.key(),YMarkTables.BOOKMARK.PUBLIC.deflt()));
data.put(YMarkTables.BOOKMARK.TAGS.key(), tagsString.getBytes());
data.put(YMarkTables.BOOKMARK.VISITS.key(), YMarkTables.BOOKMARK.VISITS.deflt().getBytes());
data.put(YMarkTables.BOOKMARK.FOLDERS.key(), foldersString.getBytes());
data.put(YMarkTables.BOOKMARK.DATE_ADDED.key(), date);
data.put(YMarkTables.BOOKMARK.DATE_MODIFIED.key(), date);
data.put(YMarkTables.BOOKMARK.DATE_VISITED.key(), date);
sb.tables.insert(bmk_table, urlHash, data);
final String[] folderArray = foldersString.split(YMarkTables.TAGS_SEPARATOR);
for (final String folder : folderArray) {
sb.tables.bookmarks.updateIndexTable(folder_table, folder, urlHash, YMarkTables.INDEX_ACTION.ADD);
}
final String[] tagArray = tagsString.split(YMarkTables.TAGS_SEPARATOR);
for (final String tag : tagArray) {
sb.tables.bookmarks.updateIndexTable(tag_table, tag, urlHash, YMarkTables.INDEX_ACTION.ADD);
}
} else {
// modify and update existing entry
bmk_row.put(YMarkTables.BOOKMARK.TITLE.key(), post.get(YMarkTables.BOOKMARK.TITLE.key(),bmk_row.get(YMarkTables.BOOKMARK.TITLE.key(),YMarkTables.BOOKMARK.TITLE.deflt())).getBytes());
bmk_row.put(YMarkTables.BOOKMARK.DESC.key(), post.get(YMarkTables.BOOKMARK.DESC.key(),bmk_row.get(YMarkTables.BOOKMARK.DESC.key(),YMarkTables.BOOKMARK.DESC.deflt())).getBytes());
bmk_row.put(YMarkTables.BOOKMARK.PUBLIC.key(), post.get(YMarkTables.BOOKMARK.PUBLIC.key(),bmk_row.get(YMarkTables.BOOKMARK.PUBLIC.key(),YMarkTables.BOOKMARK.PUBLIC.deflt())).getBytes());
HashSet<String> oldSet;
HashSet<String>newSet;
final String foldersString = YMarkTables.cleanFoldersString(post.get(YMarkTables.BOOKMARK.FOLDERS.key(),YMarkTables.BOOKMARK.FOLDERS.deflt()));
oldSet = YMarkTables.keysStringToSet(bmk_row.get(YMarkTables.BOOKMARK.FOLDERS.key(),YMarkTables.BOOKMARK.FOLDERS.deflt()));
newSet = YMarkTables.keysStringToSet(foldersString);
updateIndex(folder_table, urlHash, oldSet, newSet);
bmk_row.put(YMarkTables.BOOKMARK.FOLDERS.key(), foldersString.getBytes());
final String tagsString = YMarkTables.cleanTagsString(post.get(YMarkTables.BOOKMARK.TAGS.key(),YMarkTables.BOOKMARK.TAGS.deflt()));
oldSet = YMarkTables.keysStringToSet(bmk_row.get(YMarkTables.BOOKMARK.TAGS.key(),YMarkTables.BOOKMARK.TAGS.deflt()));
newSet = YMarkTables.keysStringToSet(tagsString);
updateIndex(tag_table, urlHash, oldSet, newSet);
bmk_row.put(YMarkTables.BOOKMARK.TAGS.key(), tagsString.getBytes());
// modify date attribute
bmk_row.put(YMarkTables.BOOKMARK.DATE_MODIFIED.key(), date);
// update bmk_table
sb.tables.update(bmk_table, bmk_row);
}
} catch (IOException e) {
Log.logException(e);
}
sb.tables.bookmarks.addBookmark(bmk_user, data, false);
} catch (IOException e) {
Log.logException(e);
} catch (RowSpaceExceededException e) {
}
prop.put("result", "1");
} else {
prop.put(YMarkTables.USER_AUTHENTICATE,YMarkTables.USER_AUTHENTICATE_MSG);
@ -135,21 +55,4 @@ public class add_ymark {
// return rewrite properties
return prop;
}
private static void updateIndex(final String index_table, final byte[] urlHash, final HashSet<String> oldSet, final HashSet<String> newSet) {
Iterator <String> tagIter;
HashSet<String> urlSet = new HashSet<String>(newSet);
newSet.removeAll(oldSet);
tagIter = newSet.iterator();
while(tagIter.hasNext()) {
sb.tables.bookmarks.updateIndexTable(index_table, tagIter.next(), urlHash, YMarkTables.INDEX_ACTION.ADD);
}
oldSet.removeAll(urlSet);
tagIter=oldSet.iterator();
while(tagIter.hasNext()) {
sb.tables.bookmarks.updateIndexTable(index_table, tagIter.next(), urlHash, YMarkTables.INDEX_ACTION.REMOVE);
}
}
}

@ -1,7 +1,6 @@
import java.io.IOException;
import net.yacy.cora.protocol.RequestHeader;
import net.yacy.kelondro.blob.Tables;
import net.yacy.kelondro.index.RowSpaceExceededException;
import net.yacy.kelondro.logging.Log;
import de.anomic.data.YMarkTables;
@ -24,12 +23,8 @@ public class delete_ymark {
final boolean isAuthUser = user!= null && user.hasRight(userDB.Entry.BOOKMARK_RIGHT);
if(isAdmin || isAuthUser) {
final String bmk_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.BOOKMARKS.basename();
final String tag_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.TAGS.basename();
final String folder_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.FOLDERS.basename();
final String bmk_user = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN);
byte[] urlHash = null;
try {
if(post.containsKey(YMarkTables.BOOKMARKS_ID)) {
urlHash = post.get(YMarkTables.BOOKMARKS_ID).getBytes();
@ -39,15 +34,7 @@ public class delete_ymark {
prop.put("result", "0");
return prop;
}
Tables.Row bmk_row = null;
bmk_row = sb.tables.select(bmk_table, urlHash);
if(bmk_row != null) {
final String tagsString = bmk_row.get(YMarkTables.BOOKMARK.TAGS.key(),YMarkTables.BOOKMARK.TAGS.deflt());
removeIndexEntry(tag_table, tagsString, urlHash);
final String foldersString = bmk_row.get(YMarkTables.BOOKMARK.FOLDERS.key(),YMarkTables.FOLDERS_ROOT);
removeIndexEntry(folder_table, foldersString, urlHash);
}
sb.tables.delete(bmk_table,urlHash);
sb.tables.bookmarks.deleteBookmark(bmk_user, urlHash);
prop.put("result", "1");
} catch (IOException e) {
Log.logException(e);
@ -60,11 +47,4 @@ public class delete_ymark {
// return rewrite properties
return prop;
}
private static void removeIndexEntry(final String index_table, String keysString, final byte[] urlHash) {
final String[] keyArray = keysString.split(YMarkTables.TAGS_SEPARATOR);
for (final String tag : keyArray) {
sb.tables.bookmarks.updateIndexTable(index_table, tag, urlHash, YMarkTables.INDEX_ACTION.REMOVE);
}
}
}

@ -30,35 +30,33 @@ public class get_ymark {
final TreeSet<String> bookmarks = new TreeSet<String>();
if(isAdmin || isAuthUser) {
final String bmk_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.BOOKMARKS.basename();
final String tag_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.TAGS.basename();
final String folder_table = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN)+YMarkTables.TABLES.FOLDERS.basename();
final String bmk_user = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN);
if(post.containsKey(YMarkTables.BOOKMARK.TAGS.key())) {
tags = true;
final String[] tagArray = YMarkTables.cleanTagsString(post.get(YMarkTables.BOOKMARK.TAGS.key())).split(YMarkTables.TAGS_SEPARATOR);
try {
bookmarks.addAll(sb.tables.bookmarks.getBookmarks(tag_table, tagArray));
bookmarks.addAll(sb.tables.bookmarks.tags.getBookmarks(bmk_user, tagArray));
} catch (IOException e) {
Log.logException(e);
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
} else if(post.containsKey(YMarkTables.BOOKMARK.FOLDERS.key())) {
}
if(post.containsKey(YMarkTables.BOOKMARK.FOLDERS.key())) {
final String[] folderArray = YMarkTables.cleanFoldersString(post.get(YMarkTables.BOOKMARK.FOLDERS.key())).split(YMarkTables.TAGS_SEPARATOR);
try {
if(tags)
bookmarks.retainAll(sb.tables.bookmarks.getBookmarks(folder_table, folderArray));
bookmarks.retainAll(sb.tables.bookmarks.folders.getBookmarks(bmk_user, folderArray));
else
bookmarks.addAll(sb.tables.bookmarks.getBookmarks(folder_table, folderArray));
bookmarks.addAll(sb.tables.bookmarks.folders.getBookmarks(bmk_user, folderArray));
} catch (IOException e) {
Log.logException(e);
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
}
putBookmarks(bookmarks, bmk_table);
putBookmarks(bookmarks, YMarkTables.TABLES.BOOKMARKS.tablename(bmk_user));
} else {
prop.put(YMarkTables.USER_AUTHENTICATE,YMarkTables.USER_AUTHENTICATE_MSG);

@ -4,6 +4,7 @@ import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import net.yacy.cora.protocol.RequestHeader;
import net.yacy.kelondro.index.RowSpaceExceededException;
import net.yacy.kelondro.logging.Log;
import de.anomic.data.YMarkTables;
import de.anomic.data.YMarksHTMLImporter;
@ -16,10 +17,8 @@ import de.anomic.server.serverSwitch;
public class import_html {
private static Switchboard sb = null;
public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) {
sb = (Switchboard) env;
final Switchboard sb = (Switchboard) env;
final serverObjects prop = new serverObjects();
final userDB.Entry user = sb.userDB.getUser(header);
final boolean isAdmin = (sb.verifyAuthentication(header, true));
@ -28,23 +27,28 @@ public class import_html {
if(isAdmin || isAuthUser) {
final String bmk_user = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN);
if(post.containsKey("htmlfile")){
ByteArrayInputStream byteIn = null;
try {
final ByteArrayInputStream byteIn = new ByteArrayInputStream(post.get("htmlfile$file").getBytes("UTF-8"));
if(byteIn !=null) {
final YMarksHTMLImporter htmlImporter = new YMarksHTMLImporter(byteIn, 100);
Thread t = new Thread(htmlImporter, "YMarks - HTML Importer");
t.start();
HashMap<String,String> bmk;
while ((bmk = htmlImporter.take()) != YMarkTables.POISON) {
sb.tables.bookmarks.addBookmark(bmk, bmk_user);
}
}
byteIn = new ByteArrayInputStream(post.get("htmlfile$file").getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
Log.logException(e);
//} catch (IOException e) {
// Log.logException(e);
}
prop.put("result", "1");
if(byteIn !=null) {
final YMarksHTMLImporter htmlImporter = new YMarksHTMLImporter(byteIn, 100);
Thread t = new Thread(htmlImporter, "YMarks - HTML Importer");
t.start();
HashMap<String,String> bmk;
while ((bmk = htmlImporter.take()) != YMarkTables.POISON) {
try {
sb.tables.bookmarks.addBookmark(bmk_user, bmk, true);
} catch (IOException e) {
Log.logWarning(YMarkTables.BOOKMARKS_LOG.toString(), "IOException for URL: "+bmk.get(YMarkTables.BOOKMARK.URL.key()));
continue;
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
}
}
}
if(post.containsKey("xbelfile")){
try {
@ -55,7 +59,11 @@ public class import_html {
t.start();
HashMap<String,String> bmk;
while ((bmk = xbelImporter.take()) != YMarkTables.POISON) {
sb.tables.bookmarks.addBookmark(bmk, bmk_user);
try {
sb.tables.bookmarks.addBookmark(bmk_user, bmk, true);
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
}
}
} catch (UnsupportedEncodingException e) {

@ -74,7 +74,7 @@ public class WorkTables extends Tables {
public void clear(final String tablename) throws IOException {
super.clear(tablename);
this.bookmarks.cleanCache(tablename);
this.bookmarks.clearIndex(tablename);
}
/**

@ -0,0 +1,224 @@
package de.anomic.data;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.regex.Pattern;
import net.yacy.cora.storage.ConcurrentARC;
import net.yacy.kelondro.blob.Tables;
import net.yacy.kelondro.blob.Tables.Data;
import net.yacy.kelondro.blob.Tables.Row;
import net.yacy.kelondro.index.RowSpaceExceededException;
import net.yacy.kelondro.logging.Log;
public class YMarkIndex {
public static enum INDEX {
ID ("id", ""),
NAME ("name", ""),
DESC ("desc", ""),
URLS ("urls", "");
private String key;
private String dflt;
private INDEX(String k, String s) {
this.key = k;
this.dflt = s;
}
public String key() {
return this.key;
}
public String deflt() {
return this.dflt;
}
}
public static enum INDEX_ACTION {
ADD,
REMOVE
}
private final WorkTables worktables;
private final String table_basename;
private final ConcurrentARC<String, byte[]> cache;
public YMarkIndex(final Tables wt, final String tb) {
this.worktables = (WorkTables)wt;
this.table_basename = tb;
this.cache = new ConcurrentARC<String, byte[]>(50,1);
}
public Iterator<String> getFolders(final String user, final String root) throws IOException {
final String index_table = user + this.table_basename;
final TreeSet<String> folders = new TreeSet<String>();
final Pattern r = Pattern.compile("^"+root);
final Iterator<Row> it = this.worktables.iterator(index_table, INDEX.NAME.key(), r);
String path = "";
Row folder;
while (it.hasNext()) {
folder = it.next();
path = new String(folder.get(INDEX.NAME.key(), INDEX.NAME.deflt()));
while(path.length() > 0 && !path.equals(root)){
folders.add(path);
path = path.replaceAll("(/.[^/]*$)", "");
}
}
if (!root.equals(YMarkTables.FOLDERS_ROOT)) { folders.add(root); }
return folders.iterator();
}
protected void clearCache() {
this.cache.clear();
}
protected void createIndexEntry(final String user, final String keyname, final HashSet<String> urlSet) throws IOException {
final byte[] key = YMarkTables.getKeyId(keyname);
final String index_table = user + this.table_basename;
final String cacheKey = index_table+":"+keyname;
final byte[] BurlSet = YMarkTables.keySetToBytes(urlSet);
Data tagEntry = new Data();
this.cache.insert(cacheKey, BurlSet);
tagEntry.put(INDEX.NAME.key, keyname);
tagEntry.put(INDEX.URLS.key, BurlSet);
this.worktables.insert(index_table, key, tagEntry);
}
protected void removeIndexEntry(final String user, String keysString, final byte[] urlHash) {
final String[] keyArray = keysString.split(YMarkTables.TAGS_SEPARATOR);
for (final String tag : keyArray) {
this.updateIndexTable(user, tag, urlHash, INDEX_ACTION.REMOVE);
}
}
protected void insertIndexEntry(final String user, String keysString, final byte[] urlHash) {
final String[] keyArray = keysString.split(YMarkTables.TAGS_SEPARATOR);
for (final String key : keyArray) {
this.updateIndexTable(user, key, urlHash, INDEX_ACTION.ADD);
}
}
protected void updateIndexEntry(final String user, final byte[] urlHash, final HashSet<String> oldSet, final HashSet<String> newSet) {
Iterator <String> tagIter;
HashSet<String> urlSet = new HashSet<String>(newSet);
newSet.removeAll(oldSet);
tagIter = newSet.iterator();
while(tagIter.hasNext()) {
this.updateIndexTable(user, tagIter.next(), urlHash, INDEX_ACTION.ADD);
}
oldSet.removeAll(urlSet);
tagIter=oldSet.iterator();
while(tagIter.hasNext()) {
this.updateIndexTable(user, tagIter.next(), urlHash, INDEX_ACTION.REMOVE);
}
}
public HashSet<String> getBookmarks(final String user, final String keyname) throws IOException, RowSpaceExceededException {
final String index_table = user + this.table_basename;
final String cacheKey = index_table+":"+keyname;
if (this.cache.containsKey(cacheKey)) {
return YMarkTables.keysStringToSet(new String(this.cache.get(cacheKey)));
} else {
final Tables.Row idx_row = this.worktables.select(index_table, YMarkTables.getKeyId(keyname));
if (idx_row != null) {
final byte[] keys = idx_row.get(INDEX.URLS.key);
this.cache.put(cacheKey, keys);
return YMarkTables.keysStringToSet(new String(keys));
}
}
return new HashSet<String>();
}
public HashSet<String> getBookmarks(final String user, final String[] keyArray) throws IOException, RowSpaceExceededException {
final HashSet<String> urlSet = new HashSet<String>();
urlSet.addAll(getBookmarks(user, keyArray[0]));
if (urlSet.isEmpty())
return urlSet;
if (keyArray.length > 1) {
for (final String keyname : keyArray) {
urlSet.retainAll(getBookmarks(user, keyname));
if (urlSet.isEmpty())
return urlSet;
}
}
return urlSet;
}
/**
* YMark function that updates the tag/folder index
* @param user
* @param keyname
* @param url is the url has as returned by DigestURI.hash()
* @param action is either add (1) or remove (2)
*/
protected void updateIndexTable(final String user, final String keyname, final byte[] url, final INDEX_ACTION action) {
final String index_table = user + this.table_basename;
final String cacheKey = index_table+":"+keyname;
final byte[] key = YMarkTables.getKeyId(keyname);
final String urlHash = new String(url);
Tables.Row row = null;
// try to load urlSet from cache
HashSet<String>urlSet = this.cache.containsKey(cacheKey) ? YMarkTables.keysStringToSet(new String(this.cache.get(cacheKey))) : new HashSet<String>();
try {
row = this.worktables.select(index_table, key);
// key has no index_table entry
if(row == null) {
switch (action) {
case ADD:
urlSet.add(urlHash);
createIndexEntry(user, keyname, urlSet);
break;
case REMOVE:
// key has no index_table entry but a cache entry
// TODO: this shouldn't happen
if(!urlSet.isEmpty()) {
urlSet.remove(urlHash);
createIndexEntry(user, keyname, urlSet);
}
break;
default:
break;
}
}
// key has an existing index_table entry
else {
byte[] BurlSet = null;
// key has no cache entry
if (urlSet.isEmpty()) {
// load urlSet from index_table
urlSet = YMarkTables.keysStringToSet(new String(row.get(INDEX.URLS.key)));
}
switch (action) {
case ADD:
urlSet.add(urlHash);
break;
case REMOVE:
urlSet.remove(urlHash);
break;
default:
break;
}
if (urlSet.isEmpty()) {
this.cache.remove(cacheKey);
this.worktables.delete(index_table, key);
} else {
BurlSet = YMarkTables.keySetToBytes(urlSet);
this.cache.insert(cacheKey, BurlSet);
row.put(INDEX.URLS.key, BurlSet);
this.worktables.update(index_table, row);
}
}
} catch (IOException e) {
Log.logException(e);
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
}
}

@ -5,13 +5,11 @@ import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import net.yacy.cora.storage.ConcurrentARC;
import net.yacy.kelondro.blob.Tables;
import net.yacy.kelondro.blob.Tables.Data;
import net.yacy.kelondro.data.meta.DigestURI;
import net.yacy.kelondro.data.word.Word;
import net.yacy.kelondro.index.RowSpaceExceededException;
import net.yacy.kelondro.logging.Log;
public class YMarkTables {
@ -87,35 +85,6 @@ public class YMarkTables {
}
}
public static enum INDEX {
ID ("id", ""),
NAME ("name", ""),
DESC ("desc", ""),
URLS ("urls", "");
private String key;
private String dflt;
private INDEX(String k, String s) {
this.key = k;
this.dflt = s;
}
public String key() {
return this.key;
}
public String deflt() {
return this.dflt;
}
public byte[] b_deflt() {
return dflt.getBytes();
}
}
public static enum INDEX_ACTION {
ADD,
REMOVE
}
public final static HashMap<String,String> POISON = new HashMap<String,String>();
public final static String TAGS_SEPARATOR = ",";
public final static String FOLDERS_SEPARATOR = "/";
@ -129,11 +98,13 @@ public class YMarkTables {
public final static String USER_AUTHENTICATE_MSG = "Authentication required!";
private WorkTables worktables;
public ConcurrentARC<String, byte[]> cache;
public YMarkIndex tags;
public YMarkIndex folders;
public YMarkTables(final Tables wt) {
this.worktables = (WorkTables)wt;
this.cache = new ConcurrentARC<String, byte[]>(50,1);
this.folders = new YMarkIndex(this.worktables, TABLES.FOLDERS.basename());
this.tags = new YMarkIndex(this.worktables, TABLES.TAGS.basename());
}
public final static byte[] getBookmarkId(String url) throws MalformedURLException {
@ -145,6 +116,10 @@ public class YMarkTables {
}
public final static byte[] keySetToBytes(final HashSet<String> urlSet) {
return keySetToString(urlSet).getBytes();
}
public final static String keySetToString(final HashSet<String> urlSet) {
final Iterator<String> urlIter = urlSet.iterator();
final
StringBuilder urls = new StringBuilder(urlSet.size()*20);
@ -153,7 +128,7 @@ public class YMarkTables {
urls.append(urlIter.next());
}
urls.deleteCharAt(0);
return urls.toString().getBytes();
return urls.toString();
}
public final static HashSet<String> keysStringToSet(final String keysString) {
@ -202,158 +177,42 @@ public class YMarkTables {
}
return fs.toString();
}
public void cleanCache(final String tablename) {
final Iterator<String> iter = this.cache.keySet().iterator();
while(iter.hasNext()) {
final String key = iter.next();
if (key.startsWith(tablename)) {
this.cache.remove(key);
}
}
}
public void createIndexEntry(final String index_table, final String keyname, final HashSet<String> urlSet) throws IOException {
final byte[] key = YMarkTables.getKeyId(keyname);
final String cacheKey = index_table+":"+keyname;
final byte[] BurlSet = keySetToBytes(urlSet);
Data tagEntry = new Data();
this.cache.insert(cacheKey, BurlSet);
tagEntry.put(INDEX.NAME.key, keyname);
tagEntry.put(INDEX.URLS.key, BurlSet);
this.worktables.insert(index_table, key, tagEntry);
public void clearIndex(String tablename) {
if (tablename.endsWith(TABLES.TAGS.basename()))
this.tags.clearCache();
if (tablename.endsWith(TABLES.FOLDERS.basename()))
this.folders.clearCache();
}
public HashSet<String> getBookmarks(final String index_table, final String keyname) throws IOException, RowSpaceExceededException {
final String cacheKey = index_table+":"+keyname;
if (this.cache.containsKey(cacheKey)) {
return keysStringToSet(new String(this.cache.get(cacheKey)));
} else {
final Tables.Row idx_row = this.worktables.select(index_table, getKeyId(keyname));
if (idx_row != null) {
final byte[] keys = idx_row.get(INDEX.URLS.key);
this.cache.put(cacheKey, keys);
return keysStringToSet(new String(keys));
}
}
return new HashSet<String>();
}
public HashSet<String> getBookmarks(final String index_table, final String[] keyArray) throws IOException, RowSpaceExceededException {
final HashSet<String> urlSet = new HashSet<String>();
urlSet.addAll(getBookmarks(index_table, keyArray[0]));
if (urlSet.isEmpty())
return urlSet;
if (keyArray.length > 1) {
for (final String keyname : keyArray) {
urlSet.retainAll(getBookmarks(index_table, keyname));
if (urlSet.isEmpty())
return urlSet;
}
}
return urlSet;
}
public void deleteBookmark(final String bmk_user, final byte[] urlHash) throws IOException, RowSpaceExceededException {
final String bmk_table = TABLES.BOOKMARKS.tablename(bmk_user);
Tables.Row bmk_row = null;
bmk_row = this.worktables.select(bmk_table, urlHash);
if(bmk_row != null) {
final String tagsString = bmk_row.get(YMarkTables.BOOKMARK.TAGS.key(),YMarkTables.BOOKMARK.TAGS.deflt());
tags.removeIndexEntry(bmk_user, tagsString, urlHash);
final String foldersString = bmk_row.get(YMarkTables.BOOKMARK.FOLDERS.key(),YMarkTables.FOLDERS_ROOT);
folders.removeIndexEntry(bmk_user, foldersString, urlHash);
this.worktables.delete(bmk_table,urlHash);
}
}
/**
* YMark function that updates the tag/folder index
* @param index_table is the user specific index
* @param keyname
* @param url is the url has as returned by DigestURI.hash()
* @param action is either add (1) or remove (2)
*/
public void updateIndexTable(final String index_table, final String keyname, final byte[] url, final INDEX_ACTION action) {
final byte[] key = YMarkTables.getKeyId(keyname);
final String urlHash = new String(url);
Tables.Row row = null;
// try to load urlSet from cache
final String cacheKey = index_table+":"+keyname;
HashSet<String>urlSet = this.cache.containsKey(cacheKey) ? keysStringToSet(new String(this.cache.get(cacheKey))) : new HashSet<String>();
try {
row = this.worktables.select(index_table, key);
// key has no index_table entry
if(row == null) {
switch (action) {
case ADD:
urlSet.add(urlHash);
createIndexEntry(index_table, keyname, urlSet);
break;
case REMOVE:
// key has no index_table entry but a cache entry
// TODO: this shouldn't happen
if(!urlSet.isEmpty()) {
urlSet.remove(urlHash);
createIndexEntry(index_table, keyname, urlSet);
}
break;
default:
break;
}
}
// key has an existing index_table entry
else {
byte[] BurlSet = null;
// key has no cache entry
if (urlSet.isEmpty()) {
// load urlSet from index_table
urlSet = keysStringToSet(new String(row.get(INDEX.URLS.key)));
}
switch (action) {
case ADD:
urlSet.add(urlHash);
break;
case REMOVE:
urlSet.remove(urlHash);
break;
default:
break;
}
if (urlSet.isEmpty()) {
this.cache.remove(cacheKey);
this.worktables.delete(index_table, key);
} else {
BurlSet = keySetToBytes(urlSet);
this.cache.insert(cacheKey, BurlSet);
row.put(INDEX.URLS.key, BurlSet);
this.worktables.update(index_table, row);
}
}
} catch (IOException e) {
Log.logException(e);
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
}
public void deleteBookmark(final String bmk_user, final String url) throws IOException, RowSpaceExceededException {
this.deleteBookmark(bmk_user, getBookmarkId(url));
}
public void addBookmark(final HashMap<String,String> bmk, final String bmk_user) {
final String bmk_table = bmk_user + TABLES.BOOKMARKS.basename();
final String folder_table = bmk_user + TABLES.FOLDERS.basename();
final String tag_table = bmk_user + TABLES.TAGS.basename();
public void addBookmark(final String bmk_user, final HashMap<String,String> bmk, final boolean importer) throws IOException, RowSpaceExceededException {
final String bmk_table = TABLES.BOOKMARKS.tablename(bmk_user);
final String date = String.valueOf(System.currentTimeMillis());
final byte[] urlHash = getBookmarkId(bmk.get(BOOKMARK.URL.key()));
Tables.Row bmk_row = null;
byte[] urlHash = null;
try {
urlHash = getBookmarkId(bmk.get(BOOKMARK.URL.key()));
} catch (MalformedURLException e) {
Log.logInfo(BOOKMARKS_LOG, "Malformed URL:"+bmk.get(BOOKMARK.URL.key()));
return;
}
if (urlHash != null) {
try {
bmk_row = this.worktables.select(bmk_table, urlHash);
} catch (IOException e) {
Log.logException(e);
} catch (RowSpaceExceededException e) {
Log.logException(e);
}
if (urlHash != null) {
bmk_row = this.worktables.select(bmk_table, urlHash);
if (bmk_row == null) {
Data data = new Data();
// create and insert new entry
final Data data = new Data();
for (BOOKMARK b : BOOKMARK.values()) {
switch(b) {
case DATE_ADDED:
@ -366,20 +225,20 @@ public class YMarkTables {
break;
case TAGS:
if(bmk.containsKey(b.key())) {
final String[] tagArray = bmk.get(b.key()).split(TAGS_SEPARATOR);
for (final String tag : tagArray) {
this.worktables.bookmarks.updateIndexTable(tag_table, tag, urlHash, INDEX_ACTION.ADD);
}
this.tags.insertIndexEntry(bmk_user, bmk.get(b.key()), urlHash);
data.put(b.key(), bmk.get(b.key()));
} else {
this.tags.insertIndexEntry(bmk_user, b.deflt(), urlHash);
data.put(b.key(), b.deflt());
}
break;
case FOLDERS:
if(bmk.containsKey(b.key())) {
final String[] folderArray = bmk.get(b.key()).split(TAGS_SEPARATOR);
for (final String folder : folderArray) {
this.worktables.bookmarks.updateIndexTable(folder_table, folder, urlHash, INDEX_ACTION.ADD);
}
this.folders.insertIndexEntry(bmk_user, bmk.get(b.key()), urlHash);
data.put(b.key(), bmk.get(b.key()));
} else {
this.folders.insertIndexEntry(bmk_user, b.deflt(), urlHash);
data.put(b.key(), b.deflt());
}
break;
default:
@ -388,13 +247,65 @@ public class YMarkTables {
}
}
}
try {
Log.logInfo(BOOKMARKS_LOG, "Add URL:"+bmk.get(BOOKMARK.URL.key()));
this.worktables.insert(bmk_table, urlHash, data);
} catch (IOException e) {
Log.logException(e);
}
}
this.worktables.insert(bmk_table, urlHash, data);
} else {
// modify and update existing entry
HashSet<String> oldSet;
HashSet<String> newSet;
for (BOOKMARK b : BOOKMARK.values()) {
switch(b) {
case DATE_ADDED:
if(!bmk_row.containsKey(b.key))
bmk_row.put(b.key(), date);
break;
case DATE_MODIFIED:
bmk_row.put(b.key(), date);
break;
case TAGS:
oldSet = keysStringToSet(bmk_row.get(b.key(),b.deflt()));
if(bmk.containsKey(b.key())) {
newSet = keysStringToSet(bmk.get(b.key()));
if(importer) {
newSet.addAll(oldSet);
bmk_row.put(b.key(), keySetToString(newSet));
oldSet.clear();
} else {
bmk_row.put(b.key, bmk.get(b.key()));
}
} else {
newSet = new HashSet<String>();
bmk_row.put(b.key, bmk_row.get(b.key(), b.deflt()));
}
this.tags.updateIndexEntry(bmk_user, urlHash, oldSet, newSet);
break;
case FOLDERS:
oldSet = keysStringToSet(bmk_row.get(b.key(),b.deflt()));
if(bmk.containsKey(b.key())) {
newSet = keysStringToSet(bmk.get(b.key()));
if(importer) {
newSet.addAll(oldSet);
bmk_row.put(b.key(), keySetToString(newSet));
oldSet.clear();
} else {
bmk_row.put(b.key, bmk.get(b.key()));
}
} else {
newSet = new HashSet<String>();
bmk_row.put(b.key, bmk_row.get(b.key(), b.deflt()));
}
this.folders.updateIndexEntry(bmk_user, urlHash, oldSet, newSet);
break;
default:
if(bmk.containsKey(b.key())) {
bmk_row.put(b.key, bmk.get(b.key()));
} else {
bmk_row.put(b.key, bmk_row.get(b.key(), b.deflt()));
}
}
}
// update bmk_table
this.worktables.update(bmk_table, bmk_row);
}
}
}
}

@ -71,6 +71,8 @@ public class YMarksHTMLImporter extends HTMLEditorKit.ParserCallback implements
case BOOKMARK:
this.bmk.put(YMarkTables.BOOKMARK.TITLE.key(), new String(data));
this.bmk.put(YMarkTables.BOOKMARK.FOLDERS.key(), this.folder);
this.bmk.put(YMarkTables.BOOKMARK.PUBLIC.key(), YMarkTables.BOOKMARK.PUBLIC.deflt());
this.bmk.put(YMarkTables.BOOKMARK.VISITS.key(), YMarkTables.BOOKMARK.VISITS.deflt());
break;
case FOLDER:
this.folder = this.folder + YMarkTables.FOLDERS_SEPARATOR + new String(data);

@ -37,6 +37,7 @@ public class YMarksXBELImporter extends DefaultHandler implements Runnable {
public static enum STATE {
NOTHING,
BOOKMARK,
INFO,
FOLDER,
FOLDER_DESC
}
@ -129,6 +130,9 @@ public class YMarksXBELImporter extends DefaultHandler implements Runnable {
return;
}
this.parsingValue = true;
} else if (XBEL.INFO.tag().equals(tag)) {
this.parsingValue = false;
this.state = STATE.INFO;
} else {
this.parsingValue = false;
this.state = STATE.NOTHING;
@ -158,6 +162,8 @@ public class YMarksXBELImporter extends DefaultHandler implements Runnable {
folder = folder.replaceAll("(/.[^/]*$)", "");
this.state = STATE.FOLDER;
}
} else if (XBEL.INFO.tag().equals(tag)) {
this.state = STATE.BOOKMARK;
}
}

Loading…
Cancel
Save