public void setFavoriteAssociations(NodeRef person, QName associtation, String type) {
   logger.debug("InFavoriteAssociationSpider.setFavoriteAssociations");
   if (null
       != preferenceService.getPreference(
           (String) nodeService.getProperty(person, ContentModel.PROP_USERNAME), type)) {
     String favorite_documents =
         preferenceService
             .getPreference(
                 (String) nodeService.getProperty(person, ContentModel.PROP_USERNAME), type)
             .toString();
     if (!favorite_documents.isEmpty()) {
       List<NodeRef> favoriteRefs = new ArrayList<>();
       for (String favorite : favorite_documents.split(",")) {
         try {
           NodeRef favoriteRef = new NodeRef(favorite);
           nodeService.getProperties(favoriteRef);
           favoriteRefs.add(favoriteRef); // new NodeRef(favorite));
         } catch (InvalidNodeRefException e) {
           // Got bad node, skipping.
         }
       }
       nodeService.setAssociations(person, associtation, favoriteRefs);
     } else {
       nodeService.setAssociations(person, associtation, new ArrayList<NodeRef>());
     }
   }
 }
  private PersonFavourite getFavouriteSite(String userName, SiteInfo siteInfo) {
    PersonFavourite favourite = null;

    String siteFavouritedKey = siteFavouritedKey(siteInfo);
    String siteCreatedAtKey = siteCreatedAtKey(siteInfo);

    Boolean isFavourited = false;
    Serializable s = preferenceService.getPreference(userName, siteFavouritedKey);
    if (s != null) {
      if (s instanceof String) {
        isFavourited = Boolean.valueOf((String) s);
      } else if (s instanceof Boolean) {
        isFavourited = (Boolean) s;
      } else {
        throw new AlfrescoRuntimeException("Unexpected favourites preference value");
      }
    }

    if (isFavourited) {
      String createdAtStr = (String) preferenceService.getPreference(userName, siteCreatedAtKey);
      Date createdAt = (createdAtStr == null ? null : ISO8601DateFormat.parse(createdAtStr));

      favourite =
          new PersonFavourite(
              userName, siteInfo.getNodeRef(), Type.SITE, siteInfo.getTitle(), createdAt);
    }

    return favourite;
  }
  private void updateFavouriteNodes(
      String userName, Type type, Map<PersonFavouriteKey, PersonFavourite> favouriteNodes) {
    PrefKeys prefKeys = getPrefKeys(type);

    Map<String, Serializable> preferences = new HashMap<String, Serializable>(1);

    StringBuilder values = new StringBuilder();
    for (PersonFavourite node : favouriteNodes.values()) {
      NodeRef nodeRef = node.getNodeRef();

      values.append(nodeRef.toString());
      values.append(",");

      // ISO8601 string format: PreferenceService works with strings only for dates it seems
      StringBuilder sb = new StringBuilder(prefKeys.getAlfrescoPrefKey());
      sb.append(nodeRef.toString());
      sb.append(".createdAt");
      String createdAtKey = sb.toString();
      Date createdAt = node.getCreatedAt();
      if (createdAt != null) {
        String createdAtStr = ISO8601DateFormat.format(createdAt);
        preferences.put(createdAtKey, createdAtStr);
      }
    }

    if (values.length() > 1) {
      values.delete(values.length() - 1, values.length());
    }

    preferences.put(prefKeys.getSharePrefKey(), values.toString());
    preferenceService.setPreferences(userName, preferences);
  }
  private PersonFavourite addFavouriteSite(String userName, NodeRef nodeRef) {
    PersonFavourite favourite = null;

    SiteInfo siteInfo = siteService.getSite(nodeRef);
    if (siteInfo != null) {
      favourite = getFavouriteSite(userName, siteInfo);
      if (favourite == null) {
        Map<String, Serializable> preferences = new HashMap<String, Serializable>(1);

        String siteFavouritedKey = siteFavouritedKey(siteInfo);
        preferences.put(siteFavouritedKey, Boolean.TRUE);

        // ISO8601 string format: PreferenceService works with strings only for dates it seems
        String siteCreatedAtKey = siteCreatedAtKey(siteInfo);
        Date createdAt = new Date();
        String createdAtStr = ISO8601DateFormat.format(createdAt);
        preferences.put(siteCreatedAtKey, createdAtStr);

        preferenceService.setPreferences(userName, preferences);

        favourite =
            new PersonFavourite(
                userName, siteInfo.getNodeRef(), Type.SITE, siteInfo.getTitle(), createdAt);

        QName nodeClass = nodeService.getType(nodeRef);
        OnAddFavouritePolicy policy = onAddFavouriteDelegate.get(nodeRef, nodeClass);
        policy.onAddFavourite(userName, nodeRef);
      }
    } else {
      // shouldn't happen, getType recognizes it as a site or subtype
      logger.warn("Unable to get site for " + nodeRef);
    }

    return favourite;
  }
  private boolean removeFavouriteSite(String userName, NodeRef nodeRef) {
    PrefKeys prefKeys = getPrefKeys(Type.SITE);
    boolean exists = false;

    SiteInfo siteInfo = siteService.getSite(nodeRef);
    if (siteInfo != null) {
      StringBuilder sitePrefKeyBuilder = new StringBuilder(prefKeys.getSharePrefKey());
      sitePrefKeyBuilder.append(siteInfo.getShortName());
      String sitePrefKey = sitePrefKeyBuilder.toString();

      String siteFavouritedKey = siteFavouritedKey(siteInfo);

      exists = preferenceService.getPreference(userName, siteFavouritedKey) != null;
      preferenceService.clearPreferences(userName, sitePrefKey);
    } else {
      throw new IllegalArgumentException("NodeRef " + nodeRef + " is not a site");
    }

    return exists;
  }
  private Map<PersonFavouriteKey, PersonFavourite> getFavouriteNodes(String userName, Type type) {
    PrefKeys prefKeys = getPrefKeys(type);
    Map<PersonFavouriteKey, PersonFavourite> favouriteNodes = Collections.emptyMap();
    Map<String, Serializable> prefs =
        preferenceService.getPreferences(userName, prefKeys.getSharePrefKey());
    String nodes = (String) prefs.get(prefKeys.getSharePrefKey());
    if (nodes != null) {
      favouriteNodes = extractFavouriteNodes(userName, type, nodes);
    } else {
      favouriteNodes = new HashMap<PersonFavouriteKey, PersonFavourite>();
    }

    return favouriteNodes;
  }
  private PersonFavourite getFavouriteDocumentOrFolder(
      String userName, Type type, NodeRef nodeRef) {
    PersonFavourite favourite = null;

    PrefKeys prefKeys = getPrefKeys(type);
    Map<String, Serializable> preferences =
        preferenceService.getPreferences(userName, prefKeys.getSharePrefKey());
    String nodes = (String) preferences.get(prefKeys.getSharePrefKey());
    if (nodes != null) {
      Map<PersonFavouriteKey, PersonFavourite> favouriteNodes =
          extractFavouriteNodes(userName, type, nodes);
      String title = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE);
      PersonFavouriteKey key = new PersonFavouriteKey(userName, title, type, nodeRef);
      favourite = favouriteNodes.get(key);
    }
    return favourite;
  }
  /*
   * Extract favourite nodes of the given type from the comma-separated list in "nodes".
   */
  private Map<PersonFavouriteKey, PersonFavourite> extractFavouriteNodes(
      String userName, Type type, String nodes) {
    PrefKeys prefKeys = getPrefKeys(type);
    Map<PersonFavouriteKey, PersonFavourite> favouriteNodes =
        new HashMap<PersonFavouriteKey, PersonFavourite>();

    StringTokenizer st = new StringTokenizer(nodes, ",");
    while (st.hasMoreTokens()) {
      String nodeRefStr = st.nextToken();
      nodeRefStr = nodeRefStr.trim();
      if (!NodeRef.isNodeRef((String) nodeRefStr)) {
        continue;
      }

      NodeRef nodeRef = new NodeRef((String) nodeRefStr);

      if (!nodeService.exists(nodeRef)) {
        continue;
      }

      if (permissionService.hasPermission(nodeRef, PermissionService.READ_PROPERTIES)
          == AccessStatus.DENIED) {
        continue;
      }

      // get createdAt for this favourited node
      // use ISO8601
      StringBuilder builder = new StringBuilder(prefKeys.getAlfrescoPrefKey());
      builder.append(nodeRef.toString());
      builder.append(".createdAt");
      String prefKey = builder.toString();
      String createdAtStr = (String) preferenceService.getPreference(userName, prefKey);
      Date createdAt = (createdAtStr != null ? ISO8601DateFormat.parse(createdAtStr) : null);

      String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);

      PersonFavourite personFavourite =
          new PersonFavourite(userName, nodeRef, type, name, createdAt);
      PersonFavouriteKey key = personFavourite.getKey();
      favouriteNodes.put(key, personFavourite);
    }

    return favouriteNodes;
  }
  private boolean isFavouriteSite(String userName, NodeRef nodeRef) {
    Boolean isFavourited = Boolean.FALSE;
    SiteInfo siteInfo = siteService.getSite(nodeRef);
    if (siteInfo != null) {
      String favouritedPrefKey = siteFavouritedKey(siteInfo);
      Serializable value = preferenceService.getPreference(userName, favouritedPrefKey);

      if (value != null) {
        if (value instanceof String) {
          isFavourited = Boolean.valueOf((String) value);
        } else if (value instanceof Boolean) {
          isFavourited = (Boolean) value;
        } else {
          throw new AlfrescoRuntimeException("Unexpected favourites preference value");
        }
      }
    } else {
      throw new IllegalArgumentException("NodeRef " + nodeRef + " is not a site");
    }

    return isFavourited.booleanValue();
  }
  @Override
  public PagingResults<PersonFavourite> getPagedFavourites(
      String userName,
      Set<Type> types,
      List<Pair<FavouritesService.SortFields, Boolean>> sortProps,
      PagingRequest pagingRequest) {
    // Get the user node reference
    final NodeRef personNodeRef = personService.getPerson(userName);
    if (personNodeRef == null) {
      throw new AlfrescoRuntimeException(
          "Can not get preferences for " + userName + " because he/she does not exist.");
    }

    boolean includeFiles = types.contains(Type.FILE);
    boolean includeFolders = types.contains(Type.FOLDER);
    boolean includeSites = types.contains(Type.SITE);

    String currentUserName = AuthenticationUtil.getFullyAuthenticatedUser();
    if (authenticationContext.isSystemUserName(currentUserName) == true
        || permissionService.hasPermission(personNodeRef, PermissionService.WRITE)
            == AccessStatus.ALLOWED
        || userName.equals(currentUserName) == true) {
      // we may have more than one favourite that is considered the same w.r.t. the PersonFavourite
      // comparator
      final Map<PersonFavouriteKey, PersonFavourite> sortedFavouriteNodes =
          new TreeMap<PersonFavouriteKey, PersonFavourite>(getComparator(sortProps));

      PrefKeys sitePrefKeys = getPrefKeys(Type.SITE);
      PrefKeys documentsPrefKeys = getPrefKeys(Type.FILE);
      PrefKeys foldersPrefKeys = getPrefKeys(Type.FOLDER);

      Map<String, Serializable> preferences = preferenceService.getPreferences(userName);
      for (String key : preferences.keySet()) {
        if (includeFiles && key.startsWith(documentsPrefKeys.sharePrefKey)) {
          String nodes = (String) preferences.get(key);
          if (nodes != null) {
            sortedFavouriteNodes.putAll(extractFavouriteNodes(userName, Type.FILE, nodes));
          }
        } else if (includeFolders && key.startsWith(foldersPrefKeys.sharePrefKey)) {
          String nodes = (String) preferences.get(key);
          if (nodes != null) {
            sortedFavouriteNodes.putAll(extractFavouriteNodes(userName, Type.FOLDER, nodes));
          }
        } else if (includeSites
            && key.startsWith(sitePrefKeys.getSharePrefKey())
            && !key.endsWith(".createdAt")) {
          // key is either of the form org.alfresco.share.sites.favourites.<siteId>.favourited or
          // org.alfresco.share.sites.favourites.<siteId>
          extractFavouriteSite(userName, Type.SITE, sortedFavouriteNodes, preferences, key);
        }
      }

      int totalSize = sortedFavouriteNodes.size();
      final PageDetails pageDetails = PageDetails.getPageDetails(pagingRequest, totalSize);

      final List<PersonFavourite> page = new ArrayList<PersonFavourite>(pageDetails.getPageSize());
      Iterator<PersonFavourite> it = sortedFavouriteNodes.values().iterator();
      for (int counter = 0; counter < pageDetails.getEnd() && it.hasNext(); counter++) {
        PersonFavourite favouriteNode = it.next();

        if (counter < pageDetails.getSkipCount()) {
          continue;
        }

        if (counter > pageDetails.getEnd() - 1) {
          break;
        }

        page.add(favouriteNode);
      }

      return new PagingResults<PersonFavourite>() {
        @Override
        public List<PersonFavourite> getPage() {
          return page;
        }

        @Override
        public boolean hasMoreItems() {
          return pageDetails.hasMoreItems();
        }

        @Override
        public Pair<Integer, Integer> getTotalResultCount() {
          Integer total = Integer.valueOf(sortedFavouriteNodes.size());
          return new Pair<Integer, Integer>(total, total);
        }

        @Override
        public String getQueryExecutionId() {
          return null;
        }
      };
    } else {
      // The current user does not have sufficient permissions to update the preferences for this
      // user
      throw new AccessDeniedException(
          "The current user "
              + currentUserName
              + " does not have sufficient permissions to get the favourites of the user "
              + userName);
    }
  }