Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit 6c04de98c648ad6b846f6ec097e66315899435c3 Florian Gutmann committed Apr 7, 2011
4 .gitignore
@@ -0,0 +1,4 @@
+.classpath
+.project
+.settings
+target
21 pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.chronimo</groupId>
+ <artifactId>bookmarks-manager</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <name>firefox-delicous</name>
+ <description>Converts a delicious bookmarks export to firefox bookmarks json.</description>
+ <dependencies>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>1.6</version>
+ </dependency>
+ </dependencies>
+</project>
74 src/main/java/com/chronimo/bookmarks/Bookmark.java
@@ -0,0 +1,74 @@
+package com.chronimo.bookmarks;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * A generic bookmark
+ *
+ * @author fgutmann
+ */
+public class Bookmark {
+
+ /**
+ * URL of the bookmark
+ */
+ private String url;
+ /**
+ * date when the bookmark was added
+ */
+ private Date addDate;
+ /**
+ * title of the bookmark
+ */
+ private String title;
+ /**
+ * long description of the bookmark
+ */
+ private String description;
+ /**
+ * tags of the bookmark
+ */
+ private List<String> tags;
+
+ public Bookmark() {}
+
+ public Bookmark(Date addDate, String url, String title, String description, List<String> tags) {
+ this.addDate = addDate;
+ this.url = url;
+ this.title = title;
+ this.description = description;
+ this.tags = tags;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+ public void setUrl(String url) {
+ this.url = url;
+ }
+ public Date getAddDate() {
+ return addDate;
+ }
+ public void setAddDate(Date addDate) {
+ this.addDate = addDate;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public void setTitle(String title) {
+ this.title = title;
+ }
+ public String getDescription() {
+ return description;
+ }
+ public void setDescription(String description) {
+ this.description = description;
+ }
+ public List<String> getTags() {
+ return tags;
+ }
+ public void setTags(List<String> tags) {
+ this.tags = tags;
+ }
+}
36 src/main/java/com/chronimo/bookmarks/BookmarksManager.java
@@ -0,0 +1,36 @@
+package com.chronimo.bookmarks;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+
+
+/**
+ * A BookmarksManager is used to manage bookmarks.
+ * This includes reading from a file, modifying and writing to a file.
+ *
+ * @author fgutmann
+ */
+public interface BookmarksManager {
+
+ /**
+ * Reads the bookmarks from the given input file.
+ */
+ public void read(File file) throws FileNotFoundException, IOException;
+
+ /**
+ * Writes the changes back to the file system.
+ */
+ public void write(File file) throws IOException;
+
+ /**
+ * Adds a bookmark to the to the Manager.
+ */
+ public void addBookmark(Bookmark bookmark);
+
+ /**
+ * Get a list of all bookmarks.
+ */
+ public List<Bookmark> getBookmarks();
+}
41 src/main/java/com/chronimo/bookmarks/Delecious2Firefox.java
@@ -0,0 +1,41 @@
+package com.chronimo.bookmarks;
+
+import java.io.File;
+import java.io.IOException;
+
+import com.chronimo.bookmarks.delicious.DeliciousManager;
+import com.chronimo.bookmarks.firefox.FirefoxManager;
+
+public class Delecious2Firefox {
+
+ public static void main(String [] args) throws IOException {
+ if (args.length < 3) {
+ System.err.println("Usage: java -jar delicious2firefox.jar <delicous.htm> <firefox.json> <outfile.json>");
+ }
+
+ File deliciousFile = new File(args[0]);
+ if (!deliciousFile.exists() || !deliciousFile.canRead()) {
+ System.err.println("Can't read the delicious file.");
+ }
+ File firefoxFile = new File(args[1]);
+ if (!firefoxFile.exists() || !firefoxFile.canRead()) {
+ System.err.println("Can't read the firefoxFile file.");
+ }
+ File outFile = new File(args[2]);
+ if (!outFile.canWrite()) {
+ System.err.println("Can't write to outFile.");
+ }
+
+ DeliciousManager delicious = new DeliciousManager();
+ delicious.read(deliciousFile);
+
+ FirefoxManager firefox = new FirefoxManager();
+ firefox.read(firefoxFile);
+
+ for (Bookmark bookmark : delicious.getBookmarks()){
+ firefox.addBookmark(bookmark);
+ }
+
+ firefox.write(outFile);
+ }
+}
75 src/main/java/com/chronimo/bookmarks/delicious/DeliciousManager.java
@@ -0,0 +1,75 @@
+package com.chronimo.bookmarks.delicious;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FileUtils;
+
+import com.chronimo.bookmarks.Bookmark;
+import com.chronimo.bookmarks.BookmarksManager;
+
+/**
+ * Implementation of a BookmarksParser for delicious htm bookmark file.
+ *
+ * @author fgutmann
+ */
+public class DeliciousManager implements BookmarksManager {
+
+ private ArrayList<Bookmark> bookmarks;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void read(File file) throws IOException {
+ List<String> lines = FileUtils.readLines(file, "UTF-8");
+ bookmarks = new ArrayList<Bookmark>(lines.size());
+
+ Pattern bookmarkPattern = Pattern.compile(".*?<DT><A HREF=\"([^\"]*)\" ADD_DATE=\"([^\"]*)\".*? TAGS=\"([^\"]*)\">([^<]*)</A>");
+ Pattern descriptionPattern = Pattern.compile("<DD>(.*)");
+
+ for (String line : lines) {
+ Matcher matcher = bookmarkPattern.matcher(line);
+ if (matcher.matches()) {
+ Bookmark bookmark = new Bookmark();
+
+ bookmark.setUrl(matcher.group(1));
+ bookmark.setAddDate(new Date(Long.parseLong(matcher.group(2))*1000));
+ bookmark.setTags(Arrays.asList(matcher.group(3).split(",")));
+ bookmark.setTitle(matcher.group(4));
+ bookmarks.add(bookmark);
+ } else {
+ matcher = descriptionPattern.matcher(line);
+ if (matcher.matches()) {
+ bookmarks.get(bookmarks.size()-1).setDescription(matcher.group(1));
+ }
+ }
+ }
+ }
+
+ /**
+ * Not implemented currently
+ */
+ public void write(File file) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ArrayList<Bookmark> getBookmarks() {
+ return bookmarks;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addBookmark(Bookmark bookmark) {
+ this.bookmarks.add(bookmark);
+ }
+}
48 src/main/java/com/chronimo/bookmarks/firefox/Annotation.java
@@ -0,0 +1,48 @@
+package com.chronimo.bookmarks.firefox;
+
+public class Annotation {
+
+ private String name;
+ private int flags;
+ private int expires;
+ private String mimeType;
+ private int type;
+ private String value;
+
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public int getFlags() {
+ return flags;
+ }
+ public void setFlags(int flags) {
+ this.flags = flags;
+ }
+ public int getExpires() {
+ return expires;
+ }
+ public void setExpires(int expires) {
+ this.expires = expires;
+ }
+ public String getMimeType() {
+ return mimeType;
+ }
+ public void setMimeType(String mimeType) {
+ this.mimeType = mimeType;
+ }
+ public int getType() {
+ return type;
+ }
+ public void setType(int type) {
+ this.type = type;
+ }
+ public String getValue() {
+ return value;
+ }
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
200 src/main/java/com/chronimo/bookmarks/firefox/FirefoxManager.java
@@ -0,0 +1,200 @@
+package com.chronimo.bookmarks.firefox;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Type;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+
+import com.chronimo.bookmarks.Bookmark;
+import com.chronimo.bookmarks.BookmarksManager;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * Implementation of BookmarksManager for the firefox browser.
+ *
+ * @author fgutmann
+ */
+public class FirefoxManager implements BookmarksManager {
+
+ private Gson gson;
+ private Node rootNode;
+
+ private int maxId;
+ private Node unsortedBookmarksNode;
+ private Node tagNode;
+ private HashMap<String, Node> tags = new HashMap<String, Node>();
+
+ private final String tagNodeRoot = "tagsFolder";
+ private final String unsortedBookmarksRoot = "unfiledBookmarksFolder";
+
+ /**
+ * Default constructor
+ */
+ public FirefoxManager() {
+ initializeGson();
+ }
+
+ /**
+ * Intializes and configures gson
+ */
+ protected void initializeGson() {
+ GsonBuilder gsonBuilder = new GsonBuilder().disableHtmlEscaping();
+
+ // Date type adapters
+ gsonBuilder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
+ public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ return new Date(json.getAsLong() / 1000);
+ }
+ });
+ gsonBuilder.registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
+ public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
+ return new JsonPrimitive(src.getTime() * 1000);
+ }
+ });
+ this.gson = gsonBuilder.create();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void read(File file) throws FileNotFoundException {
+ InputStreamReader reader = new InputStreamReader(new FileInputStream(file));
+ rootNode = gson.fromJson(reader, Node.class);
+
+ rootNode.visit(new NodeVisitor() {
+ public void visit(Node node) {
+ // find the max id
+ if (node.getId() > maxId) {
+ maxId = node.getId();
+ }
+ // find the unsorted bookmarks node
+ if (unsortedBookmarksRoot.equals(node.getRoot())) {
+ unsortedBookmarksNode = node;
+ }
+ // find the tag node
+ if (tagNodeRoot.equals(node.getRoot())) {
+ tagNode = node;
+ }
+ // build the tags map
+ if(tagNode != null && node.getParent() == tagNode.getId()) {
+ tags.put(node.getTitle(), node);
+ }
+ }
+ });
+ }
+
+ /**
+ * Writes the changes back to the file system.
+ */
+ public void write(File file) throws IOException {
+ String json = gson.toJson(rootNode);
+ FileUtils.write(file, json, "UTF-8");
+ }
+
+ /**
+ * Adds a bookmark to the manager.
+ */
+ public void addBookmark(Bookmark bookmark) {
+ Node node = new Node();
+ // Default properties
+ node.setType("text/x-moz-place");
+ node.setCharset("UTF-8");
+ node.setLastModified(new Date());
+
+ // Bookmark properties
+ node.setTitle(bookmark.getTitle());
+ node.setDateAdded(bookmark.getAddDate());
+ node.setUri(bookmark.getUrl());
+
+ // Description Annotation
+ if(bookmark.getDescription() != null) {
+ Annotation annotation = new Annotation();
+ annotation.setName("bookmarkProperties/description");
+ annotation.setFlags(0);
+ annotation.setExpires(4);
+ annotation.setMimeType(null);
+ annotation.setType(3);
+ annotation.setValue(bookmark.getDescription());
+ }
+
+ insertAsBookmark(node);
+ for(String tag : bookmark.getTags()) {
+ insertAsTag(tag, node);
+ }
+ }
+
+ /**
+ * Currently not implemented
+ */
+ public List<Bookmark> getBookmarks() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Inserts a node as bookmark
+ * @param node The node to insert
+ */
+ private void insertAsBookmark(Node node) {
+ Node copy = new Node(node);
+ insertNode(copy, unsortedBookmarksNode);
+ }
+
+ /**
+ * Inserts a node as a tag
+ * @param tagString The tag in form of a string
+ * @param node The node to insert
+ */
+ private void insertAsTag(String tagString, Node node) {
+ Node copy = new Node(node);
+ copy.setAnnos(null);
+
+ Node tagNode = this.tags.get(tagString);
+ if (tagNode == null) {
+ tagNode = createTagNode(tagString);
+ }
+ insertNode(copy, tagNode);
+ }
+
+ /**
+ * Creates a new tag node
+ */
+ private Node createTagNode(String tagString) {
+ Date now = new Date();
+ Node node = new Node();
+ node.setTitle(tagString);
+ node.setDateAdded(now);
+ node.setLastModified(now);
+ node.setType("text/x-moz-place-container");
+
+ insertNode(node, this.tagNode);
+ this.tags.put(tagString, node);
+ return node;
+ }
+
+ /**
+ * Inserts a node as child of another node
+ * @param node Node to insert
+ * @param parent The parent node
+ */
+ private void insertNode(Node node, Node parent) {
+ node.setId(++ maxId);
+ node.setParent(parent.getId());
+
+ parent.insert(node);
+ }
+}
132 src/main/java/com/chronimo/bookmarks/firefox/Node.java
@@ -0,0 +1,132 @@
+package com.chronimo.bookmarks.firefox;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Node {
+
+ private String title;
+ private int id;
+ private Integer parent;
+ private Date dateAdded;
+ private Date lastModified;
+ private String type;
+ private String root;
+ private String uri;
+ private String charset;
+ private List<Annotation> annos;
+ private List<Node> children;
+
+ /**
+ * Default constructor
+ */
+ public Node() {}
+
+ /**
+ * Copy constructor
+ * @param node
+ */
+ public Node(Node node) {
+ this.title = node.title;
+ this.id = node.id;
+ this.parent = node.parent;
+ this.dateAdded = node.dateAdded;
+ this.lastModified = node.lastModified;
+ this.type = node.type;
+ this.root = node.root;
+ this.children = node.children;
+ this.uri = node.uri;
+ this.annos = node.annos;
+ this.charset = node.charset;
+ }
+
+ /**
+ * Visit all nodes recursive from top to bottom
+ */
+ public void visit(NodeVisitor visitor) {
+ visitor.visit(this);
+ if (children != null) {
+ for (Node child : children) {
+ child.visit(visitor);
+ }
+ }
+ }
+
+ /**
+ * Inserts a node as child
+ */
+ public void insert(Node node) {
+ if (children == null) {
+ children = new LinkedList<Node>();
+ }
+ children.add(node);
+ }
+
+ public String getTitle() {
+ return title;
+ }
+ public void setTitle(String title) {
+ this.title = title;
+ }
+ public int getId() {
+ return id;
+ }
+ public void setId(int id) {
+ this.id = id;
+ }
+ public Integer getParent() {
+ return parent;
+ }
+ public void setParent(Integer parent) {
+ this.parent = parent;
+ }
+ public Date getDateAdded() {
+ return dateAdded;
+ }
+ public void setDateAdded(Date dateAdded) {
+ this.dateAdded = dateAdded;
+ }
+ public Date getLastModified() {
+ return lastModified;
+ }
+ public void setLastModified(Date lastModified) {
+ this.lastModified = lastModified;
+ }
+ public String getType() {
+ return type;
+ }
+ public void setType(String type) {
+ this.type = type;
+ }
+ public String getRoot() {
+ return root;
+ }
+ public void setRoot(String root) {
+ this.root = root;
+ }
+ public List<Node> getChildren() {
+ return children;
+ }
+ public void setChildren(List<Node> children) {
+ this.children = children;
+ }
+ public String getUri() {
+ return uri;
+ }
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+ public List<Annotation> getAnnos() {
+ return annos;
+ }
+ public void setAnnos(List<Annotation> annos) {
+ this.annos = annos;
+ }
+ public String getCharset() {
+ return charset;
+ }
+ public void setCharset(String charset) {
+ this.charset = charset;
+ }
+}
9 src/main/java/com/chronimo/bookmarks/firefox/NodeVisitor.java
@@ -0,0 +1,9 @@
+package com.chronimo.bookmarks.firefox;
+
+/**
+ * Visitor for a node
+ * @author fgutmann
+ */
+public interface NodeVisitor {
+ public void visit(Node node);
+}

0 comments on commit 6c04de9

Please sign in to comment.
Something went wrong with that request. Please try again.