BookmarkManager.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smackx.bookmarks;

  18. import java.util.Collections;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.WeakHashMap;

  23. import org.jivesoftware.smack.SmackException.NoResponseException;
  24. import org.jivesoftware.smack.SmackException.NotConnectedException;
  25. import org.jivesoftware.smack.XMPPConnection;
  26. import org.jivesoftware.smack.XMPPException.XMPPErrorException;

  27. import org.jivesoftware.smackx.iqprivate.PrivateDataManager;

  28. import org.jxmpp.jid.EntityBareJid;
  29. import org.jxmpp.jid.parts.Resourcepart;


  30. /**
  31.  * Provides methods to manage bookmarks in accordance with XEP-0048. Methods for managing URLs and
  32.  * Conferences are provided.
  33.  *
  34.  * It should be noted that some extensions have been made to the XEP. There is an attribute on URLs
  35.  * that marks a url as a news feed and also a sub-element can be added to either a URL or conference
  36.  * indicated that it is shared amongst all users on a server.
  37.  *
  38.  * @author Alexander Wenckus
  39.  */
  40. public final class BookmarkManager {
  41.     private static final Map<XMPPConnection, BookmarkManager> bookmarkManagerMap = new WeakHashMap<>();

  42.     static {
  43.         PrivateDataManager.addPrivateDataProvider("storage", "storage:bookmarks",
  44.                 new Bookmarks.Provider());
  45.     }

  46.     /**
  47.      * Returns the <i>BookmarkManager</i> for a connection, if it doesn't exist it is created.
  48.      *
  49.      * @param connection the connection for which the manager is desired.
  50.      * @return Returns the <i>BookmarkManager</i> for a connection, if it doesn't
  51.      * exist it is created.
  52.      * @throws IllegalArgumentException when the connection is null.
  53.      */
  54.     public static synchronized BookmarkManager getBookmarkManager(XMPPConnection connection) {
  55.         BookmarkManager manager = bookmarkManagerMap.get(connection);
  56.         if (manager == null) {
  57.             manager = new BookmarkManager(connection);
  58.             bookmarkManagerMap.put(connection, manager);
  59.         }
  60.         return manager;
  61.     }

  62.     private final PrivateDataManager privateDataManager;
  63.     private Bookmarks bookmarks;
  64.     private final Object bookmarkLock = new Object();

  65.     /**
  66.      * Default constructor. Registers the data provider with the private data manager in the
  67.      * storage:bookmarks namespace.
  68.      *
  69.      * @param connection the connection for persisting and retrieving bookmarks.
  70.      */
  71.     private BookmarkManager(XMPPConnection connection) {
  72.         privateDataManager = PrivateDataManager.getInstanceFor(connection);
  73.     }

  74.     /**
  75.      * Returns all currently bookmarked conferences.
  76.      *
  77.      * @return returns all currently bookmarked conferences
  78.      * @throws XMPPErrorException if there was an XMPP error returned.
  79.      * @throws NoResponseException if there was no response from the remote entity.
  80.      * @throws NotConnectedException if the XMPP connection is not connected.
  81.      * @throws InterruptedException if the calling thread was interrupted.
  82.      * @see BookmarkedConference
  83.      */
  84.     public List<BookmarkedConference> getBookmarkedConferences() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  85.         retrieveBookmarks();
  86.         return Collections.unmodifiableList(bookmarks.getBookmarkedConferences());
  87.     }

  88.     /**
  89.      * Adds or updates a conference in the bookmarks.
  90.      *
  91.      * @param name the name of the conference
  92.      * @param jid the jid of the conference
  93.      * @param isAutoJoin whether or not to join this conference automatically on login
  94.      * @param nickname the nickname to use for the user when joining the conference
  95.      * @param password the password to use for the user when joining the conference
  96.      * @throws XMPPErrorException thrown when there is an issue retrieving the current bookmarks from
  97.      * the server.
  98.      * @throws NoResponseException if there was no response from the server.
  99.      * @throws NotConnectedException if the XMPP connection is not connected.
  100.      * @throws InterruptedException if the calling thread was interrupted.
  101.      */
  102.     public void addBookmarkedConference(String name, EntityBareJid jid, boolean isAutoJoin,
  103.             Resourcepart nickname, String password) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  104.         retrieveBookmarks();
  105.         BookmarkedConference bookmark
  106.                 = new BookmarkedConference(name, jid, isAutoJoin, nickname, password);
  107.         List<BookmarkedConference> conferences = bookmarks.getBookmarkedConferences();
  108.         if (conferences.contains(bookmark)) {
  109.             BookmarkedConference oldConference = conferences.get(conferences.indexOf(bookmark));
  110.             if (oldConference.isShared()) {
  111.                 throw new IllegalArgumentException("Cannot modify shared bookmark");
  112.             }
  113.             oldConference.setAutoJoin(isAutoJoin);
  114.             oldConference.setName(name);
  115.             oldConference.setNickname(nickname);
  116.             oldConference.setPassword(password);
  117.         }
  118.         else {
  119.             bookmarks.addBookmarkedConference(bookmark);
  120.         }
  121.         privateDataManager.setPrivateData(bookmarks);
  122.     }

  123.     /**
  124.      * Removes a conference from the bookmarks.
  125.      *
  126.      * @param jid the jid of the conference to be removed.
  127.      * @throws XMPPErrorException thrown when there is a problem with the connection attempting to
  128.      * retrieve the bookmarks or persist the bookmarks.
  129.      * @throws NoResponseException if there was no response from the server.
  130.      * @throws NotConnectedException if the XMPP connection is not connected.
  131.      * @throws InterruptedException if the calling thread was interrupted.
  132.      * @throws IllegalArgumentException thrown when the conference being removed is a shared
  133.      * conference
  134.      */
  135.     public void removeBookmarkedConference(EntityBareJid jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  136.         retrieveBookmarks();
  137.         Iterator<BookmarkedConference> it = bookmarks.getBookmarkedConferences().iterator();
  138.         while (it.hasNext()) {
  139.             BookmarkedConference conference = it.next();
  140.             if (conference.getJid().equals(jid)) {
  141.                 if (conference.isShared()) {
  142.                     throw new IllegalArgumentException("Conference is shared and can't be removed");
  143.                 }
  144.                 it.remove();
  145.                 privateDataManager.setPrivateData(bookmarks);
  146.                 return;
  147.             }
  148.         }
  149.     }

  150.     /**
  151.      * Returns an unmodifiable collection of all bookmarked urls.
  152.      *
  153.      * @return returns an unmodifiable collection of all bookmarked urls.
  154.      * @throws XMPPErrorException thrown when there is a problem retriving bookmarks from the server.
  155.      * @throws NoResponseException if there was no response from the server.
  156.      * @throws NotConnectedException if the XMPP connection is not connected.
  157.      * @throws InterruptedException if the calling thread was interrupted.
  158.      */
  159.     public List<BookmarkedURL> getBookmarkedURLs() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  160.         retrieveBookmarks();
  161.         return Collections.unmodifiableList(bookmarks.getBookmarkedURLS());
  162.     }

  163.     /**
  164.      * Adds a new url or updates an already existing url in the bookmarks.
  165.      *
  166.      * @param URL the url of the bookmark
  167.      * @param name the name of the bookmark
  168.      * @param isRSS whether or not the url is an rss feed
  169.      * @throws XMPPErrorException thrown when there is an error retriving or saving bookmarks from or to
  170.      * the server
  171.      * @throws NoResponseException if there was no response from the server.
  172.      * @throws NotConnectedException if the XMPP connection is not connected.
  173.      * @throws InterruptedException if the calling thread was interrupted.
  174.      */
  175.     public void addBookmarkedURL(String URL, String name, boolean isRSS) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  176.         retrieveBookmarks();
  177.         BookmarkedURL bookmark = new BookmarkedURL(URL, name, isRSS);
  178.         List<BookmarkedURL> urls = bookmarks.getBookmarkedURLS();
  179.         if (urls.contains(bookmark)) {
  180.             BookmarkedURL oldURL = urls.get(urls.indexOf(bookmark));
  181.             if (oldURL.isShared()) {
  182.                 throw new IllegalArgumentException("Cannot modify shared bookmarks");
  183.             }
  184.             oldURL.setName(name);
  185.             oldURL.setRss(isRSS);
  186.         }
  187.         else {
  188.             bookmarks.addBookmarkedURL(bookmark);
  189.         }
  190.         privateDataManager.setPrivateData(bookmarks);
  191.     }

  192.     /**
  193.      *  Removes a url from the bookmarks.
  194.      *
  195.      * @param bookmarkURL the url of the bookmark to remove
  196.      * @throws XMPPErrorException thrown if there is an error retriving or saving bookmarks from or to
  197.      * the server.
  198.      * @throws NoResponseException if there was no response from the server.
  199.      * @throws NotConnectedException if the XMPP connection is not connected.
  200.      * @throws InterruptedException if the calling thread was interrupted.
  201.      */
  202.     public void removeBookmarkedURL(String bookmarkURL) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  203.         retrieveBookmarks();
  204.         Iterator<BookmarkedURL> it = bookmarks.getBookmarkedURLS().iterator();
  205.         while (it.hasNext()) {
  206.             BookmarkedURL bookmark = it.next();
  207.             if (bookmark.getURL().equalsIgnoreCase(bookmarkURL)) {
  208.                 if (bookmark.isShared()) {
  209.                     throw new IllegalArgumentException("Cannot delete a shared bookmark.");
  210.                 }
  211.                 it.remove();
  212.                 privateDataManager.setPrivateData(bookmarks);
  213.                 return;
  214.             }
  215.         }
  216.     }

  217.     /**
  218.      * Check if the service supports bookmarks using private data.
  219.      *
  220.      * @return true if the service supports private data, false otherwise.
  221.      * @throws NoResponseException if there was no response from the remote entity.
  222.      * @throws NotConnectedException if the XMPP connection is not connected.
  223.      * @throws InterruptedException if the calling thread was interrupted.
  224.      * @throws XMPPErrorException if there was an XMPP error returned.
  225.      * @see PrivateDataManager#isSupported()
  226.      * @since 4.2
  227.      */
  228.     public boolean isSupported() throws NoResponseException, NotConnectedException,
  229.                     XMPPErrorException, InterruptedException {
  230.         return privateDataManager.isSupported();
  231.     }

  232.     private Bookmarks retrieveBookmarks() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  233.         synchronized (bookmarkLock) {
  234.             if (bookmarks == null) {
  235.                 bookmarks = (Bookmarks) privateDataManager.getPrivateData("storage",
  236.                         "storage:bookmarks");
  237.             }
  238.             return bookmarks;
  239.         }
  240.     }
  241. }