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