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