gt:         for (String user : mentionedUsernames) {
context: /**
   * Copyright (C) 2011  JTalks.org Team
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
   */
  package org.jtalks.jcommune.service.nontransactional;
  
  import org.apache.commons.collections.CollectionUtils;
  import org.apache.commons.lang.StringUtils;
  import org.jtalks.jcommune.model.dao.PostDao;
  import org.jtalks.jcommune.model.dao.UserDao;
  import org.jtalks.jcommune.model.entity.JCUser;
  import org.jtalks.jcommune.model.entity.Post;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.web.context.request.RequestAttributes;
  import org.springframework.web.context.request.RequestContextHolder;
  import org.springframework.web.context.request.ServletRequestAttributes;
  
  import javax.servlet.http.HttpServletRequest;
  import java.util.*;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import static java.lang.String.format;
  
  
  /**
   * This service provides send email notifications to all mentioned users
   * in some components of forum:topics, posts. Also it provides an ability
   * to extract users mentioning from text.
   *
   * @author Anuar_Nurmakanov
   * @author Andrei Alikov
   */
  public class MentionedUsers {
      public static final String MENTIONED_NOT_NOTIFIED_USER_TEMPLATE = "[user]%s[/user]";
      public static final String MENTIONED_AND_NOTIFIED_USER_TEMPLATE = "[user notified=true]%s[/user]";
      public static final String USER_WITH_LINK_TO_PROFILE_TEMPLATE = "[user=%s]%s[/user]";
      private static final Logger LOGGER = LoggerFactory.getLogger(MentionedUsers.class);
      private static final Pattern ALL_MENTIONED_USERS_PATTERN =
              Pattern.compile("\\[user\\].+?(\\[/user\\])+|\\[user notified=true\\].+?(\\[/user\\])+");
      private static final Pattern MENTIONED_AND_NOT_NOTIFIED_USERS_PATTERN =
              Pattern.compile("\\[user\\].+?(\\[/user\\])+");
      private static final String CLOSE_BRACKET_CODE_PLACEHOLDER = "@w0956756wo@";
      private static final String OPEN_BRACKET_CODE_PLACEHOLDER = "@ywdffgg434y@";
      private static final String SLASH_CODE_PLACEHOLDER = "14@123435vggv4f";
      private static final String LOWER_THEN_PLACEHOLDER = "gertfgertgf@@@@@#4324234";
      private static final Map<String, String> CHARS_PLACEHOLDERS = new HashMap<>();
  
      static {
          CHARS_PLACEHOLDERS.put("[", OPEN_BRACKET_CODE_PLACEHOLDER);
          CHARS_PLACEHOLDERS.put("]", CLOSE_BRACKET_CODE_PLACEHOLDER);
          CHARS_PLACEHOLDERS.put("\\", SLASH_CODE_PLACEHOLDER);
          CHARS_PLACEHOLDERS.put("<", LOWER_THEN_PLACEHOLDER);
      }
  
      private final Map<String, String> encodedUserNames = new HashMap<>();
      /**
       * Content of the post
       */
      private String postContent;
      /**
       * Post with mentioned users
       */
      private Post post;
  
      private MentionedUsers(String postContent) {
          this.postContent = postContent;
      }
  
      private MentionedUsers(Post post) {
          this.post = post;
          this.postContent = post.getPostContent();
      }
  
      /**
       * Creates new instance of MentionedUsers based on the Post data
       *
       * @param postContent content of the post where user was mentioned
       */
      public static MentionedUsers parse(String postContent) {
          return new MentionedUsers(postContent);
      }
  
      /**
       * Creates new instance of MentionedUsers based on the Post data
       *
       * @param post the post where user was mentioned
       */
      public static MentionedUsers parse(Post post) {
          return new MentionedUsers(post);
      }
  
      /**
       * Get list of the users which have to receive notification
       *
       * @param userDao service for user related operations
       * @return list of the users which should be notified that they were mentioned
       * @throws IllegalStateException when instance was not created based on Post object
       */
      public List<JCUser> getNewUsersToNotify(UserDao userDao) {
          if (post == null) {
              throw new IllegalStateException("To call this method you should create class with Post type parameter");
          }
  
          Set<String> mentionedUsersNames = extractNotNotifiedMentionedUsers(postContent);
          if (!CollectionUtils.isEmpty(mentionedUsersNames)) {
              return getNewUsersToNotify(mentionedUsersNames, userDao);
          }
  
          return new ArrayList<>();
      }
  
      /**
       * Marks all users in user BB codes as already notified
       *
       * @param postDao service for post related operations
       * @throws IllegalStateException when instance was not created based on Post object
       */
      public void markUsersAsAlreadyNotified(PostDao postDao) {
          if (post == null) {
              throw new IllegalStateException("To call this method you should create class with Post type parameter");
          }
  
          Set<String> mentionedUsersNames = extractNotNotifiedMentionedUsers(postContent);
          if (!CollectionUtils.isEmpty(mentionedUsersNames)) {
              markUsersAsAlreadyNotified(mentionedUsersNames, postDao);
          }
      }
  
      /**
       * Returns post text with BB codes replaced by user profile links
       *
       * @param userDao service for working with user objects
       * @return text with BB codes replaced by user profile links
       */
      public String getTextWithProcessedUserTags(UserDao userDao) {
          Set<String> mentionedUsers = extractAllMentionedUsers(postContent);
          Map<String, String> userToUserProfileLinkMap = new HashMap<>();
          for (String mentionedUser : mentionedUsers) {
              String mentionedUserProfileLink = getLinkToUserProfile(mentionedUser, userDao);
              userToUserProfileLinkMap.put(mentionedUser, mentionedUserProfileLink);
          }
          return addLinksToUserProfileForMentionedUsers(postContent, userToUserProfileLinkMap);
      }
  
      /**
       * Extract names of all users that were mentioned in passed text.
       *
       * @return extracted users' names
       */
      public Set<String> extractAllMentionedUsers(String canContainMentionedUsers) {
          return extractMentionedUsers(canContainMentionedUsers, ALL_MENTIONED_USERS_PATTERN);
      }
  
      /**
       * Extract names of users that were mentioned but not notified yet
       *
       * @return names of users that were mentioned but not notified yet
       */
      private Set<String> extractNotNotifiedMentionedUsers(String canContainMentionedUsers) {
          return extractMentionedUsers(canContainMentionedUsers, MENTIONED_AND_NOT_NOTIFIED_USERS_PATTERN);
      }
  
      /**
       * Extract names of users that were mentioned in passed text.
       *
       * @param canContainMentionedUsers can contain users mentioning
       * @param mentionedUserPattern     pattern to extract mentioned user in given text
       * @return extracted users' names
       */
      private Set<String> extractMentionedUsers(String canContainMentionedUsers, Pattern mentionedUserPattern) {
          if (!StringUtils.isEmpty(canContainMentionedUsers)) {
              Matcher matcher = mentionedUserPattern.matcher(canContainMentionedUsers);
              Set<String> mentionedUsernames = new HashSet<>();
              while (matcher.find()) {
                  String userBBCode = matcher.group();
                  String mentionedUser;
                  if (userBBCode.contains("[user notified=true]")) {
                      mentionedUser = StringUtils.substring(userBBCode, 20, userBBCode.length() - 7);
                  } else {
                      mentionedUser = StringUtils.substring(userBBCode, 6, userBBCode.length() - 7);
                  }
                  mentionedUsernames.add(replacePlaceholdersWithChars(mentionedUser));
              }
              return mentionedUsernames;
          }
          return Collections.emptySet();
      }
  
      private String replacePlaceholdersWithChars(String userNameWithPlaceholders) {
          String formattedUserName = userNameWithPlaceholders;
          for (Map.Entry<String, String> decodeEntry : CHARS_PLACEHOLDERS.entrySet()) {
              formattedUserName = formattedUserName.replace(decodeEntry.getValue(), decodeEntry.getKey());
          }
          encodedUserNames.put(formattedUserName, userNameWithPlaceholders);
          return formattedUserName;
      }
  
      private String encodeUsername(String decodedUsername) {
          return encodedUserNames.get(decodedUsername);
      }
  
      /**
       * Gets list of users which should be notified
       *
       * @param mentionedUsernames the set of names of mentioned users
       * @param userDao            service for working with JCUser objects
       * @return list of users which should be notified
       */
      private List<JCUser> getNewUsersToNotify(Set<String> mentionedUsernames, UserDao userDao) {
          List<JCUser> mentionedUsers = userDao.getByUsernames(mentionedUsernames);
          List<JCUser> usersToNotify = new ArrayList<>();
  
          for (JCUser mentionedUser : mentionedUsers) {
              if (shouldNotificationBeSent(mentionedUser)) {
                  usersToNotify.add(mentionedUser);
              }
          }
  
          return usersToNotify;
      }
  
      /**
       * Determines if it is needed to send notification to the user
       *
       * @param mentionedUser this user was mentioned
       * @return true if we need to send notification and false otherwise
       */
      private boolean shouldNotificationBeSent(JCUser mentionedUser) {
          boolean isOtherNotificationAlreadySent = post.getSubscribers().contains(mentionedUser);
          return !isOtherNotificationAlreadySent && mentionedUser.isMentioningNotificationsEnabled();
      }
  
      /**
       * Mark user tags as already notified
       *
       * @param mentionedUsernames the set of names of mentioned users
       * @param postDao            service for working with Post objects
       */
      private void markUsersAsAlreadyNotified(Set<String> mentionedUsernames, PostDao postDao) {
  