001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.data.osm; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.util.ArrayList; 007 import java.util.HashMap; 008 import java.util.HashSet; 009 import java.util.List; 010 import java.util.concurrent.atomic.AtomicLong; 011 012 import org.openstreetmap.josm.tools.Utils; 013 014 /** 015 * A simple class to keep a list of user names. 016 * 017 * Instead of storing user names as strings with every OSM primitive, we store 018 * a reference to an user object, and make sure that for each username there 019 * is only one user object. 020 * 021 * 022 */ 023 public class User { 024 025 static private AtomicLong uidCounter = new AtomicLong(); 026 027 /** 028 * the map of known users 029 */ 030 private static HashMap<Long,User> userMap = new HashMap<Long,User>(); 031 private final static User anonymous = createLocalUser(tr("<anonymous>")); 032 033 private static long getNextLocalUid() { 034 return uidCounter.decrementAndGet(); 035 } 036 037 /** 038 * Creates a local user with the given name 039 * 040 * @param name the name 041 */ 042 public static User createLocalUser(String name) { 043 for(long i = -1; i >= uidCounter.get(); --i) 044 { 045 User olduser = getById(i); 046 if(olduser != null && olduser.hasName(name)) 047 return olduser; 048 } 049 User user = new User(getNextLocalUid(), name); 050 userMap.put(user.getId(), user); 051 return user; 052 } 053 054 /** 055 * Creates a user known to the OSM server 056 * 057 * @param uid the user id 058 * @param name the name 059 */ 060 public static User createOsmUser(long uid, String name) { 061 User user = userMap.get(uid); 062 if (user == null) { 063 user = new User(uid, name); 064 userMap.put(user.getId(), user); 065 } 066 if (name != null) user.addName(name); 067 return user; 068 } 069 070 /** 071 * clears the static map of user ids to user objects 072 * 073 */ 074 public static void clearUserMap() { 075 userMap.clear(); 076 } 077 078 /** 079 * Returns the user with user id <code>uid</code> or null if this user doesn't exist 080 * 081 * @param uid the user id 082 * @return the user; null, if there is no user with this id 083 */ 084 public static User getById(long uid) { 085 return userMap.get(uid); 086 } 087 088 /** 089 * Returns the list of users with name <code>name</code> or the empty list if 090 * no such users exist 091 * 092 * @param name the user name 093 * @return the list of users with name <code>name</code> or the empty list if 094 * no such users exist 095 */ 096 public static List<User> getByName(String name) { 097 if (name == null) { 098 name = ""; 099 } 100 List<User> ret = new ArrayList<User>(); 101 for (User user: userMap.values()) { 102 if (user.hasName(name)) { 103 ret.add(user); 104 } 105 } 106 return ret; 107 } 108 109 public static User getAnonymous() { 110 return anonymous; 111 } 112 113 /** the user name */ 114 private final HashSet<String> names = new HashSet<String>(); 115 /** the user id */ 116 private final long uid; 117 118 /** 119 * Replies the user name 120 * 121 * @return the user name. Never null, but may be the empty string 122 */ 123 public String getName() { 124 return Utils.join("/", names); 125 } 126 127 /** 128 * Returns the list of user names 129 * 130 * @returns list of names 131 */ 132 public ArrayList<String> getNames() { 133 return new ArrayList<String>(names); 134 } 135 136 /** 137 * Adds a user name to the list if it is not there, yet. 138 * 139 * @param name 140 */ 141 public void addName(String name) { 142 names.add(name); 143 } 144 145 /** 146 * Returns true if the name is in the names list 147 * 148 * @param name 149 */ 150 public boolean hasName(String name) { 151 return names.contains(name); 152 } 153 154 /** 155 * Replies the user id. If this user is known to the OSM server the positive user id 156 * from the server is replied. Otherwise, a negative local value is replied. 157 * 158 * A negative local is only unique during an editing session. It is lost when the 159 * application is closed and there is no guarantee that a negative local user id is 160 * always bound to a user with the same name. 161 * 162 */ 163 public long getId() { 164 return uid; 165 } 166 167 /** private constructor, only called from get method. */ 168 private User(long uid, String name) { 169 this.uid = uid; 170 if (name != null) { 171 addName(name); 172 } 173 } 174 175 public boolean isOsmUser() { 176 return uid > 0; 177 } 178 179 public boolean isLocalUser() { 180 return uid < 0; 181 } 182 183 @Override 184 public int hashCode() { 185 final int prime = 31; 186 int result = 1; 187 result = prime * result + getName().hashCode(); 188 result = prime * result + (int) (uid ^ (uid >>> 32)); 189 return result; 190 } 191 192 @Override 193 public boolean equals(Object obj) { 194 if (! (obj instanceof User)) 195 return false; 196 User other = (User) obj; 197 if (uid != other.uid) 198 return false; 199 return true; 200 } 201 202 @Override 203 public String toString() { 204 StringBuffer s = new StringBuffer(); 205 s.append("id:"+uid); 206 if (names.size() == 1) { 207 s.append(" name:"+getName()); 208 } 209 else if (names.size() > 1) { 210 s.append(String.format(" %d names:%s", names.size(), getName())); 211 } 212 return s.toString(); 213 } 214 }