001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.jivesoftware.smackx.bookmarks; 019 020import java.util.Collections; 021import java.util.Iterator; 022import java.util.List; 023import java.util.Map; 024import java.util.WeakHashMap; 025 026import org.jivesoftware.smack.SmackException; 027import org.jivesoftware.smack.SmackException.NoResponseException; 028import org.jivesoftware.smack.SmackException.NotConnectedException; 029import org.jivesoftware.smack.XMPPConnection; 030import org.jivesoftware.smack.XMPPException; 031import org.jivesoftware.smack.XMPPException.XMPPErrorException; 032import org.jivesoftware.smackx.iqprivate.PrivateDataManager; 033 034 035/** 036 * Provides methods to manage bookmarks in accordance with XEP-0048. Methods for managing URLs and 037 * Conferences are provided. 038 * </p> 039 * It should be noted that some extensions have been made to the XEP. There is an attribute on URLs 040 * that marks a url as a news feed and also a sub-element can be added to either a URL or conference 041 * indicated that it is shared amongst all users on a server. 042 * 043 * @author Alexander Wenckus 044 */ 045public class BookmarkManager { 046 private static final Map<XMPPConnection, BookmarkManager> bookmarkManagerMap = new WeakHashMap<XMPPConnection, BookmarkManager>(); 047 048 static { 049 PrivateDataManager.addPrivateDataProvider("storage", "storage:bookmarks", 050 new Bookmarks.Provider()); 051 } 052 053 /** 054 * Returns the <i>BookmarkManager</i> for a connection, if it doesn't exist it is created. 055 * 056 * @param connection the connection for which the manager is desired. 057 * @return Returns the <i>BookmarkManager</i> for a connection, if it doesn't 058 * exist it is created. 059 * @throws XMPPException 060 * @throws SmackException thrown has not been authenticated. 061 * @throws IllegalArgumentException when the connection is null. 062 */ 063 public synchronized static BookmarkManager getBookmarkManager(XMPPConnection connection) 064 throws XMPPException, SmackException 065 { 066 BookmarkManager manager = (BookmarkManager) bookmarkManagerMap.get(connection); 067 if (manager == null) { 068 manager = new BookmarkManager(connection); 069 } 070 return manager; 071 } 072 073 private PrivateDataManager privateDataManager; 074 private Bookmarks bookmarks; 075 private final Object bookmarkLock = new Object(); 076 077 /** 078 * Default constructor. Registers the data provider with the private data manager in the 079 * storage:bookmarks namespace. 080 * 081 * @param connection the connection for persisting and retrieving bookmarks. 082 */ 083 private BookmarkManager(XMPPConnection connection) throws XMPPException, SmackException { 084 privateDataManager = PrivateDataManager.getInstanceFor(connection); 085 bookmarkManagerMap.put(connection, this); 086 } 087 088 /** 089 * Returns all currently bookmarked conferences. 090 * 091 * @return returns all currently bookmarked conferences 092 * @throws XMPPErrorException 093 * @throws NoResponseException 094 * @throws NotConnectedException 095 * @see BookmarkedConference 096 */ 097 public List<BookmarkedConference> getBookmarkedConferences() throws NoResponseException, XMPPErrorException, NotConnectedException { 098 retrieveBookmarks(); 099 return Collections.unmodifiableList(bookmarks.getBookmarkedConferences()); 100 } 101 102 /** 103 * Adds or updates a conference in the bookmarks. 104 * 105 * @param name the name of the conference 106 * @param jid the jid of the conference 107 * @param isAutoJoin whether or not to join this conference automatically on login 108 * @param nickname the nickname to use for the user when joining the conference 109 * @param password the password to use for the user when joining the conference 110 * @throws XMPPErrorException thrown when there is an issue retrieving the current bookmarks from 111 * the server. 112 * @throws NoResponseException if there was no response from the server. 113 * @throws NotConnectedException 114 */ 115 public void addBookmarkedConference(String name, String jid, boolean isAutoJoin, 116 String nickname, String password) throws NoResponseException, XMPPErrorException, NotConnectedException 117 { 118 retrieveBookmarks(); 119 BookmarkedConference bookmark 120 = new BookmarkedConference(name, jid, isAutoJoin, nickname, password); 121 List<BookmarkedConference> conferences = bookmarks.getBookmarkedConferences(); 122 if(conferences.contains(bookmark)) { 123 BookmarkedConference oldConference = conferences.get(conferences.indexOf(bookmark)); 124 if(oldConference.isShared()) { 125 throw new IllegalArgumentException("Cannot modify shared bookmark"); 126 } 127 oldConference.setAutoJoin(isAutoJoin); 128 oldConference.setName(name); 129 oldConference.setNickname(nickname); 130 oldConference.setPassword(password); 131 } 132 else { 133 bookmarks.addBookmarkedConference(bookmark); 134 } 135 privateDataManager.setPrivateData(bookmarks); 136 } 137 138 /** 139 * Removes a conference from the bookmarks. 140 * 141 * @param jid the jid of the conference to be removed. 142 * @throws XMPPErrorException thrown when there is a problem with the connection attempting to 143 * retrieve the bookmarks or persist the bookmarks. 144 * @throws NoResponseException if there was no response from the server. 145 * @throws NotConnectedException 146 * @throws IllegalArgumentException thrown when the conference being removed is a shared 147 * conference 148 */ 149 public void removeBookmarkedConference(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException { 150 retrieveBookmarks(); 151 Iterator<BookmarkedConference> it = bookmarks.getBookmarkedConferences().iterator(); 152 while(it.hasNext()) { 153 BookmarkedConference conference = it.next(); 154 if(conference.getJid().equalsIgnoreCase(jid)) { 155 if(conference.isShared()) { 156 throw new IllegalArgumentException("Conference is shared and can't be removed"); 157 } 158 it.remove(); 159 privateDataManager.setPrivateData(bookmarks); 160 return; 161 } 162 } 163 } 164 165 /** 166 * Returns an unmodifiable collection of all bookmarked urls. 167 * 168 * @return returns an unmodifiable collection of all bookmarked urls. 169 * @throws XMPPErrorException thrown when there is a problem retriving bookmarks from the server. 170 * @throws NoResponseException if there was no response from the server. 171 * @throws NotConnectedException 172 */ 173 public List<BookmarkedURL> getBookmarkedURLs() throws NoResponseException, XMPPErrorException, NotConnectedException { 174 retrieveBookmarks(); 175 return Collections.unmodifiableList(bookmarks.getBookmarkedURLS()); 176 } 177 178 /** 179 * Adds a new url or updates an already existing url in the bookmarks. 180 * 181 * @param URL the url of the bookmark 182 * @param name the name of the bookmark 183 * @param isRSS whether or not the url is an rss feed 184 * @throws XMPPErrorException thrown when there is an error retriving or saving bookmarks from or to 185 * the server 186 * @throws NoResponseException if there was no response from the server. 187 * @throws NotConnectedException 188 */ 189 public void addBookmarkedURL(String URL, String name, boolean isRSS) throws NoResponseException, XMPPErrorException, NotConnectedException { 190 retrieveBookmarks(); 191 BookmarkedURL bookmark = new BookmarkedURL(URL, name, isRSS); 192 List<BookmarkedURL> urls = bookmarks.getBookmarkedURLS(); 193 if(urls.contains(bookmark)) { 194 BookmarkedURL oldURL = urls.get(urls.indexOf(bookmark)); 195 if(oldURL.isShared()) { 196 throw new IllegalArgumentException("Cannot modify shared bookmarks"); 197 } 198 oldURL.setName(name); 199 oldURL.setRss(isRSS); 200 } 201 else { 202 bookmarks.addBookmarkedURL(bookmark); 203 } 204 privateDataManager.setPrivateData(bookmarks); 205 } 206 207 /** 208 * Removes a url from the bookmarks. 209 * 210 * @param bookmarkURL the url of the bookmark to remove 211 * @throws XMPPErrorException thrown if there is an error retriving or saving bookmarks from or to 212 * the server. 213 * @throws NoResponseException if there was no response from the server. 214 * @throws NotConnectedException 215 */ 216 public void removeBookmarkedURL(String bookmarkURL) throws NoResponseException, XMPPErrorException, NotConnectedException { 217 retrieveBookmarks(); 218 Iterator<BookmarkedURL> it = bookmarks.getBookmarkedURLS().iterator(); 219 while(it.hasNext()) { 220 BookmarkedURL bookmark = it.next(); 221 if(bookmark.getURL().equalsIgnoreCase(bookmarkURL)) { 222 if(bookmark.isShared()) { 223 throw new IllegalArgumentException("Cannot delete a shared bookmark."); 224 } 225 it.remove(); 226 privateDataManager.setPrivateData(bookmarks); 227 return; 228 } 229 } 230 } 231 232 private Bookmarks retrieveBookmarks() throws NoResponseException, XMPPErrorException, NotConnectedException { 233 synchronized(bookmarkLock) { 234 if(bookmarks == null) { 235 bookmarks = (Bookmarks) privateDataManager.getPrivateData("storage", 236 "storage:bookmarks"); 237 } 238 return bookmarks; 239 } 240 } 241}