1 package com.atlassian.user.util.migration;
2
3 import java.sql.Connection;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 import java.util.HashMap;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Map;
10
11 import javax.sql.DataSource;
12
13 import com.atlassian.user.security.password.Credential;
14 import net.sf.hibernate.HibernateException;
15 import net.sf.hibernate.Session;
16 import net.sf.hibernate.SessionFactory;
17
18 import org.apache.log4j.Logger;
19 import org.springframework.jdbc.core.JdbcTemplate;
20 import org.springframework.jdbc.core.RowCallbackHandler;
21 import org.springframework.jdbc.datasource.SingleConnectionDataSource;
22 import org.springframework.orm.hibernate.SessionFactoryUtils;
23
24 import com.atlassian.user.EntityException;
25 import com.atlassian.user.ExternalEntity;
26 import com.atlassian.user.Group;
27 import com.atlassian.user.GroupManager;
28 import com.atlassian.user.User;
29 import com.atlassian.user.UserManager;
30 import com.atlassian.user.configuration.DefaultDelegationAccessor;
31 import com.atlassian.user.configuration.DelegationAccessor;
32 import com.atlassian.user.configuration.RepositoryAccessor;
33 import com.atlassian.user.impl.DefaultUser;
34 import com.atlassian.user.impl.RepositoryException;
35 import com.atlassian.user.impl.hibernate.DefaultExternalEntityDAO;
36 import com.atlassian.user.impl.hibernate.DefaultHibernateUser;
37 import com.atlassian.user.impl.hibernate.properties.HibernatePropertySetFactory;
38 import com.atlassian.user.impl.osuser.OSUAccessor;
39 import com.atlassian.user.impl.osuser.OSUUserManager;
40 import com.opensymphony.user.provider.AccessProvider;
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class OSUEntityMigrator implements EntityMigrator
55 {
56 private static final Logger log = Logger.getLogger(OSUEntityMigrator.class);
57
58 private static final String OSUSER_REPOSITORY_KEY = "osuserRepository";
59
60 private UserManager targetUserManager;
61 private GroupManager targetGroupManager;
62
63 private AccessProvider osAccessProvider;
64
65 private final SessionFactory sessionFactory;
66
67 private final DefaultExternalEntityDAO externalEntityDAO;
68
69
70
71
72
73 private Session hibernateSession;
74
75 public OSUEntityMigrator(RepositoryAccessor osuserRepositoryAccessor, RepositoryAccessor repositoryAccessor, SessionFactory sessionFactory)
76 {
77 if (osuserRepositoryAccessor == null)
78 throw new IllegalArgumentException("osuserRepositoryAccessor is required.");
79 if (repositoryAccessor == null)
80 throw new IllegalArgumentException("targetRepositoryAccessor is required.");
81 if (sessionFactory == null)
82 throw new IllegalArgumentException("sessionFactory is required.");
83
84 this.sessionFactory = sessionFactory;
85 this.externalEntityDAO = new DefaultExternalEntityDAO(sessionFactory);
86
87 final DelegationAccessor targetRepositoryAccessor = getNonOSUserRepositoryAccessor(repositoryAccessor);
88 if (!targetRepositoryAccessor.getRepositoryAccessors().isEmpty())
89 {
90 final UserManager osUserManager = osuserRepositoryAccessor.getUserManager();
91 if (osUserManager == null)
92 throw new IllegalArgumentException("osUserManager is required.");
93
94 final OSUAccessor osuAccessor = ((OSUUserManager) osUserManager).getAccessor();
95 if (osuAccessor == null)
96 throw new IllegalArgumentException("osuAccessor is required.");
97
98 osAccessProvider = osuAccessor.getAccessProvider();
99 if (osAccessProvider == null)
100 throw new IllegalArgumentException("osAccessProvider is required.");
101
102 targetUserManager = targetRepositoryAccessor.getUserManager();
103 targetGroupManager = targetRepositoryAccessor.getGroupManager();
104
105 if (targetUserManager == null)
106 throw new IllegalArgumentException("userManager is required.");
107 if (targetGroupManager == null)
108 throw new IllegalArgumentException("groupManager is required.");
109 }
110 }
111
112 private DelegationAccessor getNonOSUserRepositoryAccessor(RepositoryAccessor repositoryAccessor)
113 {
114 final DelegationAccessor nonOSUserDelegationAccessor = new DefaultDelegationAccessor();
115 if (repositoryAccessor instanceof DelegationAccessor)
116 {
117 final DelegationAccessor delegationAccessor = (DelegationAccessor) repositoryAccessor;
118 for (Iterator iterator = delegationAccessor.getRepositoryAccessors().iterator(); iterator.hasNext();)
119 {
120 final RepositoryAccessor accessor = (RepositoryAccessor) iterator.next();
121 if (!OSUSER_REPOSITORY_KEY.equals(accessor.getIdentifier().getKey()))
122 nonOSUserDelegationAccessor.addRepositoryAccessor(accessor);
123 }
124 return nonOSUserDelegationAccessor;
125 }
126 else
127 {
128 if (!OSUSER_REPOSITORY_KEY.equals(repositoryAccessor.getIdentifier().getKey()))
129 nonOSUserDelegationAccessor.addRepositoryAccessor(repositoryAccessor);
130 }
131 return nonOSUserDelegationAccessor;
132 }
133
134 public boolean hasExistingUsers()
135 {
136 try
137 {
138 return !targetUserManager.getUsers().isEmpty();
139 }
140 catch (EntityException e)
141 {
142 throw new RuntimeException(e);
143 }
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157 public void migrate(MigratorConfiguration config, MigrationProgressListener progressListener) throws EntityException
158 {
159 if (targetUserManager == null)
160 {
161 throw new RepositoryException("No non OSUser repository configured. Cannot perform migration.");
162 }
163
164 hibernateSession = SessionFactoryUtils.getSession(sessionFactory, true);
165
166 OSUserDao osUserDao = new OSUserDao(getDataSource());
167 final Map<Long, DefaultUser> users = osUserDao.findAllUsers();
168 final Map<String, List<String>> userGroups = osUserDao.findAllUserGroups(users);
169 Map<User, Boolean> migratedUsers = migrateUsers(progressListener, users);
170
171
172 for (Iterator<Map.Entry<User,Boolean>> it = migratedUsers.entrySet().iterator(); it.hasNext();)
173 {
174 Map.Entry<User,Boolean> userEntry = it.next();
175 final User user = userEntry.getKey();
176 migrateUserGroupMembership(user, userGroups.get(user.getName()), (userEntry.getValue()).booleanValue(), config, progressListener);
177 }
178
179
180
181 migrateGroups(progressListener);
182 }
183
184 private Map<User, Boolean> migrateUsers(MigrationProgressListener progressListener, Map<Long, DefaultUser> users)
185 throws EntityException
186 {
187
188 progressListener.userMigrationStarted(users.size());
189
190 Map<User, Boolean> migratedUsers = new HashMap<User, Boolean>();
191
192 int i = 0;
193 for (Iterator<Map.Entry<Long,DefaultUser>> it = users.entrySet().iterator(); it.hasNext(); i++)
194 {
195 Map.Entry<Long,DefaultUser> userEntry = it.next();
196 final Long osUserId = userEntry.getKey();
197 final User user = userEntry.getValue();
198
199 User existingUser = targetUserManager.getUser(user.getName());
200 if(existingUser == null)
201 {
202 User newUser = addUser(targetUserManager, (DefaultUser) user);
203 migratedUsers.put(newUser, Boolean.TRUE);
204 }
205 else
206 {
207 migratedUsers.put(existingUser, Boolean.FALSE);
208 }
209 migratePropertySet(osUserId, user);
210
211
212 progressListener.userMigrated();
213 if (i % 100 == 0){
214 try
215 {
216 hibernateSession.flush();
217 hibernateSession.clear();
218 }
219 catch (HibernateException e)
220 {
221 log.error(e);
222 }
223 }
224 }
225
226 progressListener.userMigrationComplete();
227 return migratedUsers;
228 }
229
230 private void migrateGroups(MigrationProgressListener progressListener)
231 throws EntityException
232 {
233 final List groups = osAccessProvider.list();
234 progressListener.groupMigrationStarted(groups.size());
235
236 for (Iterator groupsIterator = groups.iterator(); groupsIterator.hasNext();)
237 {
238 final String groupName = (String) groupsIterator.next();
239 getOrCreateGroup(groupName);
240 progressListener.groupMigrated();
241 }
242
243 progressListener.groupMigrationComplete();
244 }
245
246 private void migrateUserGroupMembership(User user, List<String> userGroups, boolean isCreatedUser, MigratorConfiguration config,
247 MigrationProgressListener progressListener) throws EntityException
248 {
249 if (userGroups != null){
250 for(Iterator<String> iter = userGroups.iterator(); iter.hasNext();){
251 String groupName = iter.next();
252 Group group = getOrCreateGroup(groupName);
253 if (isCreatedUser || config.isMigrateMembershipsForExistingUsers())
254 {
255 if (log.isInfoEnabled()) log.info("Adding member <" + user.getName() + "> to group <" + groupName + ">");
256 if (!targetGroupManager.isReadOnly(group))
257 {
258 targetGroupManager.addMembership(group, user);
259 }
260 else
261 {
262 progressListener.readonlyGroupMembershipNotMigrated(group.getName(), user.getName());
263 }
264 }
265 }
266 }
267 }
268
269 private void migratePropertySet(Long userId, User user) throws EntityException
270 {
271 if (log.isInfoEnabled()) log.info("Migrating properties for <" + user.getName() + ">");
272
273 final User targetUser = targetUserManager.getUser(user.getName());
274 final String entityName = getEntityName(targetUser);
275 final long entityId = getEntityId(targetUser);
276
277 final JdbcTemplate template = new JdbcTemplate(getDataSource());
278
279 if (template.queryForInt("SELECT count(*) FROM OS_PROPERTYENTRY WHERE entity_name=? AND entity_id=?", new Object[] {entityName, new Long(entityId)}) == 0)
280 {
281 template.query("SELECT * FROM OS_PROPERTYENTRY WHERE entity_name = 'OSUser_user' AND entity_id = ? AND entity_key <> 'fullName' AND entity_key <> 'email'", new Object[]{userId}, new RowCallbackHandler()
282 {
283 public void processRow(ResultSet resultSet) throws SQLException
284 {
285 template.update("INSERT INTO OS_PROPERTYENTRY (entity_name,entity_id,entity_key,key_type,boolean_val,double_val,string_val,long_val,int_val,date_val) VALUES (?,?,?,?,?,?,?,?,?,?)", new Object[]{
286 entityName,
287 new Long(entityId),
288 resultSet.getString("entity_key"),
289 new Integer(resultSet.getInt("key_type")),
290 Boolean.valueOf(resultSet.getBoolean("boolean_val")),
291 new Double(resultSet.getDouble("double_val")),
292 resultSet.getString("string_val"),
293 new Long(resultSet.getLong("long_val")),
294 new Integer(resultSet.getInt("int_val")),
295 resultSet.getTimestamp("date_val")
296 });
297 }
298 });
299 }
300 }
301
302 private String getEntityName(User user) throws EntityException
303 {
304 if (isExternalUser(user))
305 {
306 return HibernatePropertySetFactory.EXTERNAL_ENTITY + "_" + user.getName();
307 }
308 return HibernatePropertySetFactory.LOCAL_USER + "_" + user.getName();
309 }
310
311 private long getEntityId(User user) throws EntityException
312 {
313 if (!isExternalUser(user))
314 {
315 return ((DefaultHibernateUser) user).getId();
316 }
317 ExternalEntity externalEntity = externalEntityDAO.getExternalEntity(user.getName());
318 if (externalEntity != null)
319 {
320 return externalEntity.getId();
321 }
322 return externalEntityDAO.createExternalEntity(user.getName()).getId();
323 }
324
325 private boolean isExternalUser(User user)
326 {
327 return !(user instanceof DefaultHibernateUser);
328 }
329
330
331
332
333
334
335
336
337 private User addUser(UserManager userManager, DefaultUser user) throws EntityException
338 {
339 if (log.isInfoEnabled()) log.info("Adding user <" + user.getName() + ">");
340 Credential credential = user.getPassword() == null ?
341 Credential.NONE :
342 Credential.encrypted(user.getPassword());
343 if (user.getFullName() == null) user.setFullName("");
344 if (user.getEmail() == null) user.setEmail("");
345 return userManager.createUser(user, credential);
346 }
347
348 private Group getOrCreateGroup(String groupName) throws EntityException
349 {
350 Group group = targetGroupManager.getGroup(groupName);
351 if (group == null)
352 {
353 if (log.isInfoEnabled()) log.info("Creating group <" + groupName + ">");
354 group = targetGroupManager.createGroup(groupName);
355 }
356
357 return group;
358 }
359
360 private DataSource getDataSource()
361 {
362 Connection conn;
363 try
364 {
365 conn = hibernateSession.connection();
366 }
367 catch (HibernateException e)
368 {
369 throw new RuntimeException(e);
370 }
371 return new SingleConnectionDataSource(conn, true);
372 }
373 }