PageRenderTime 62ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersDataSource.java

https://github.com/galderz/rhq
Java | 349 lines | 252 code | 61 blank | 36 comment | 19 complexity | c6e2f4beb68013f4fde63498f7a65e57 MD5 | raw file
  1. /*
  2. * RHQ Management Platform
  3. * Copyright (C) 2005-2010 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation version 2 of the License.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. package org.rhq.enterprise.gui.coregui.client.admin.users;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import com.google.gwt.user.client.rpc.AsyncCallback;
  24. import com.smartgwt.client.data.DSRequest;
  25. import com.smartgwt.client.data.DSResponse;
  26. import com.smartgwt.client.data.DataSourceField;
  27. import com.smartgwt.client.data.Record;
  28. import com.smartgwt.client.data.fields.DataSourceIntegerField;
  29. import com.smartgwt.client.data.fields.DataSourcePasswordField;
  30. import com.smartgwt.client.data.fields.DataSourceTextField;
  31. import com.smartgwt.client.types.FieldType;
  32. import com.smartgwt.client.widgets.form.validator.LengthRangeValidator;
  33. import com.smartgwt.client.widgets.form.validator.MatchesFieldValidator;
  34. import com.smartgwt.client.widgets.form.validator.RegExpValidator;
  35. import com.smartgwt.client.widgets.grid.ListGridRecord;
  36. import org.rhq.core.domain.auth.Subject;
  37. import org.rhq.core.domain.criteria.SubjectCriteria;
  38. import org.rhq.core.domain.util.PageList;
  39. import org.rhq.enterprise.gui.coregui.client.admin.roles.RolesDataSource;
  40. import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
  41. import org.rhq.enterprise.gui.coregui.client.gwt.SubjectGWTServiceAsync;
  42. import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
  43. /**
  44. * A DataSource for RHQ {@link Subject user}s.
  45. *
  46. * @author Greg Hinkle
  47. * @author Ian Springer
  48. */
  49. public class UsersDataSource extends RPCDataSource<Subject, SubjectCriteria> {
  50. private static UsersDataSource INSTANCE;
  51. private static final String EMAIL_ADDRESS_REGEXP = "^([a-zA-Z0-9_.\\-+])+@([a-zA-Z0-9\\-])+(\\.([a-zA-Z0-9\\-])+)*$";
  52. private static final String MASKED_PASSWORD_VALUE = "XXXXXXXX";
  53. public static abstract class Field {
  54. public static final String ID = "id";
  55. public static final String NAME = "name";
  56. public static final String FIRST_NAME = "firstName";
  57. public static final String LAST_NAME = "lastName";
  58. public static final String FACTIVE = "factive";
  59. public static final String FSYSTEM = "fsystem";
  60. public static final String DEPARTMENT = "department";
  61. public static final String PHONE_NUMBER = "phoneNumber";
  62. public static final String EMAIL_ADDRESS = "emailAddress";
  63. public static final String ROLES = "roles";
  64. // auth-related fields
  65. public static final String LDAP = "ldap";
  66. public static final String PASSWORD = "password";
  67. public static final String PASSWORD_VERIFY = "passwordVerify";
  68. }
  69. public static final int ID_OVERLORD = 1;
  70. public static final int ID_RHQADMIN = 2;
  71. private final SubjectGWTServiceAsync subjectService = GWTServiceLookup.getSubjectService();
  72. public static UsersDataSource getInstance() {
  73. if (INSTANCE == null) {
  74. INSTANCE = new UsersDataSource();
  75. }
  76. return INSTANCE;
  77. }
  78. public static boolean isSystemSubjectId(int subjectId) {
  79. return (subjectId == ID_OVERLORD || subjectId == ID_RHQADMIN);
  80. }
  81. public UsersDataSource() {
  82. List<DataSourceField> fields = addDataSourceFields();
  83. addFields(fields);
  84. }
  85. @Override
  86. protected List<DataSourceField> addDataSourceFields() {
  87. List<DataSourceField> fields = super.addDataSourceFields();
  88. DataSourceField idDataField = new DataSourceIntegerField(Field.ID, "ID");
  89. idDataField.setPrimaryKey(true);
  90. idDataField.setCanEdit(false);
  91. fields.add(idDataField);
  92. DataSourceTextField usernameField = createTextField(Field.NAME, MSG.dataSource_users_field_name(), 3, 100, true);
  93. // Don't allow characters that could be used in HTML intended for an XSS attack.
  94. RegExpValidator regExpValidator = new RegExpValidator("[^&<]*");
  95. usernameField.setValidators(regExpValidator);
  96. fields.add(usernameField);
  97. DataSourceTextField ldapField = createBooleanField(Field.LDAP, MSG.dataSource_users_field_ldap(), true);
  98. ldapField.setCanEdit(false); // read-only
  99. fields.add(ldapField);
  100. DataSourcePasswordField passwordField = new DataSourcePasswordField(Field.PASSWORD,
  101. MSG.common_title_password(), 100, true);
  102. LengthRangeValidator passwordValidator = new LengthRangeValidator();
  103. passwordValidator.setMin(6);
  104. passwordValidator.setMax(100);
  105. passwordField.setValidators(passwordValidator);
  106. fields.add(passwordField);
  107. DataSourcePasswordField passwordVerifyField = new DataSourcePasswordField(Field.PASSWORD_VERIFY, MSG
  108. .dataSource_users_field_passwordVerify(), 100, true);
  109. MatchesFieldValidator passwordsEqualValidator = new MatchesFieldValidator();
  110. passwordsEqualValidator.setOtherField(Field.PASSWORD);
  111. passwordsEqualValidator.setErrorMessage(MSG.dataSource_users_passwordsDoNotMatch());
  112. passwordVerifyField.setValidators(passwordsEqualValidator);
  113. fields.add(passwordVerifyField);
  114. DataSourceTextField firstNameField = createTextField(Field.FIRST_NAME, MSG.dataSource_users_field_firstName(),
  115. null, 100, true);
  116. fields.add(firstNameField);
  117. DataSourceTextField lastNameField = createTextField(Field.LAST_NAME, MSG.dataSource_users_field_lastName(),
  118. null, 100, true);
  119. fields.add(lastNameField);
  120. DataSourceTextField emailAddressField = createTextField(Field.EMAIL_ADDRESS, MSG
  121. .dataSource_users_field_emailAddress(), null, 100, true);
  122. fields.add(emailAddressField);
  123. RegExpValidator emailAddressValidator = new RegExpValidator(EMAIL_ADDRESS_REGEXP);
  124. emailAddressValidator.setErrorMessage(MSG.dataSource_users_invalidEmailAddress());
  125. emailAddressField.setValidators(emailAddressValidator);
  126. DataSourceTextField phoneNumberField = createTextField(Field.PHONE_NUMBER, MSG
  127. .dataSource_users_field_phoneNumber(), null, 100, false);
  128. fields.add(phoneNumberField);
  129. DataSourceTextField departmentField = createTextField(Field.DEPARTMENT,
  130. MSG.dataSource_users_field_department(), null, 100, false);
  131. fields.add(departmentField);
  132. DataSourceTextField enabledField = createBooleanField(Field.FACTIVE, MSG.dataSource_users_field_factive(), true);
  133. fields.add(enabledField);
  134. DataSourceField rolesField = new DataSourceField(Field.ROLES, FieldType.ANY, "Roles");
  135. fields.add(rolesField);
  136. return fields;
  137. }
  138. @Override
  139. public void executeFetch(final DSRequest request, final DSResponse response, final SubjectCriteria criteria) {
  140. subjectService.findSubjectsByCriteria(criteria, new AsyncCallback<PageList<Subject>>() {
  141. public void onFailure(Throwable caught) {
  142. String message = "Failed to fetch user(s).";
  143. sendFailureResponse(request, response, message, caught);
  144. }
  145. public void onSuccess(final PageList<Subject> fetchedSubjects) {
  146. final PageList<Record> userRecordsPageList = new PageList<Record>(fetchedSubjects.getPageControl());
  147. userRecordsPageList.setTotalSize(fetchedSubjects.getTotalSize());
  148. userRecordsPageList.setUnbounded(fetchedSubjects.isUnbounded());
  149. final boolean[] failed = { false };
  150. for (int i = 0, fetchedSubjectsSize = fetchedSubjects.size(); i < fetchedSubjectsSize; i++) {
  151. if (failed[0]) {
  152. break;
  153. }
  154. final Subject fetchedSubject = fetchedSubjects.get(i);
  155. final String username = fetchedSubject.getName();
  156. subjectService.isUserWithPrincipal(username, new AsyncCallback<Boolean>() {
  157. public void onFailure(Throwable caught) {
  158. failed[0] = true;
  159. String message = "Failed to check if user [" + username + "] is an LDAP user.";
  160. sendFailureResponse(request, response, message, caught);
  161. }
  162. public void onSuccess(Boolean hasPrincipal) {
  163. boolean isLdap = (!hasPrincipal);
  164. Record userRecord = copyUserValues(fetchedSubject, isLdap);
  165. userRecordsPageList.add(userRecord);
  166. if (userRecordsPageList.size() == fetchedSubjects.size()) {
  167. sendSuccessResponseRecords(request, response, userRecordsPageList);
  168. }
  169. }
  170. });
  171. }
  172. }
  173. });
  174. }
  175. @Override
  176. protected void executeAdd(final Record recordToAdd, final DSRequest request, final DSResponse response) {
  177. final Subject newSubject = copyValues(recordToAdd);
  178. String password = recordToAdd.getAttribute(Field.PASSWORD);
  179. subjectService.createSubject(newSubject, password, new AsyncCallback<Subject>() {
  180. public void onFailure(Throwable caught) {
  181. // TODO: Throw more specific SLSB exceptions so we can set the right validation errors.
  182. String message = caught.getMessage();
  183. if (message != null && message.contains("javax.persistence.EntityExistsException")) {
  184. Map<String, String> errorMessages = new HashMap<String, String>();
  185. errorMessages.put(Field.NAME, "A user named [" + newSubject.getName() + "] already exists.");
  186. sendValidationErrorResponse(request, response, errorMessages);
  187. } else {
  188. throw new RuntimeException(caught);
  189. }
  190. }
  191. public void onSuccess(final Subject createdSubject) {
  192. Record createdUserRecord = copyUserValues(createdSubject, false);
  193. sendSuccessResponse(request, response, createdUserRecord);
  194. }
  195. });
  196. }
  197. @Override
  198. protected void executeUpdate(final Record editedUserRecord, Record oldUserRecord, final DSRequest request,
  199. final DSResponse response) {
  200. Subject editedSubject = copyValues(editedUserRecord);
  201. final String username = editedSubject.getName();
  202. final String editedPassword = editedUserRecord.getAttributeAsString(Field.PASSWORD);
  203. boolean passwordWasEdited = !MASKED_PASSWORD_VALUE.equals(editedPassword);
  204. String newPassword = (passwordWasEdited) ? editedPassword : null;
  205. subjectService.updateSubject(editedSubject, newPassword, new AsyncCallback<Subject>() {
  206. public void onFailure(Throwable caught) {
  207. String message = "Failed to update user [" + username + "].";
  208. sendFailureResponse(request, response, message, caught);
  209. }
  210. public void onSuccess(final Subject updatedSubject) {
  211. sendSuccessResponse(request, response, editedUserRecord);
  212. }
  213. });
  214. }
  215. public Subject copyValues(Record from) {
  216. Subject to = new Subject();
  217. to.setId(from.getAttributeAsInt(Field.ID));
  218. to.setName(from.getAttributeAsString(Field.NAME));
  219. to.setFirstName(from.getAttributeAsString(Field.FIRST_NAME));
  220. to.setLastName(from.getAttributeAsString(Field.LAST_NAME));
  221. to.setFactive(Boolean.valueOf(from.getAttributeAsString(Field.FACTIVE)));
  222. to.setFsystem(Boolean.valueOf(from.getAttributeAsString(Field.FSYSTEM)));
  223. to.setDepartment(from.getAttributeAsString(Field.DEPARTMENT));
  224. to.setPhoneNumber(from.getAttributeAsString(Field.PHONE_NUMBER));
  225. to.setEmailAddress(from.getAttributeAsString(Field.EMAIL_ADDRESS));
  226. Record[] roleRecords = from.getAttributeAsRecordArray(Field.ROLES);
  227. to.setRoles(RolesDataSource.getInstance().buildDataObjects(roleRecords));
  228. return to;
  229. }
  230. public Record copyUserValues(Subject subject, boolean isLdap) {
  231. ListGridRecord targetRecord = copyValues(subject);
  232. targetRecord.setAttribute(Field.LDAP, isLdap);
  233. // Leave the password fields blank if username is null (i.e. it's a new user).
  234. if (subject.getName() != null) {
  235. targetRecord.setAttribute(Field.PASSWORD, MASKED_PASSWORD_VALUE);
  236. targetRecord.setAttribute(Field.PASSWORD_VERIFY, MASKED_PASSWORD_VALUE);
  237. }
  238. return targetRecord;
  239. }
  240. public ListGridRecord copyValues(Subject from) {
  241. return copyValues(from, true);
  242. }
  243. @Override
  244. public ListGridRecord copyValues(Subject from, boolean cascade) {
  245. ListGridRecord to = new ListGridRecord();
  246. to.setAttribute(Field.ID, from.getId());
  247. to.setAttribute(Field.NAME, from.getName());
  248. to.setAttribute(Field.FIRST_NAME, from.getFirstName());
  249. to.setAttribute(Field.LAST_NAME, from.getLastName());
  250. to.setAttribute(Field.FACTIVE, from.getFactive());
  251. to.setAttribute(Field.FSYSTEM, from.getFsystem());
  252. to.setAttribute(Field.DEPARTMENT, from.getDepartment());
  253. to.setAttribute(Field.PHONE_NUMBER, from.getPhoneNumber());
  254. to.setAttribute(Field.EMAIL_ADDRESS, from.getEmailAddress());
  255. if (cascade) {
  256. ListGridRecord[] roleRecords = RolesDataSource.getInstance().buildRecords(from.getRoles(), false);
  257. to.setAttribute(Field.ROLES, roleRecords);
  258. }
  259. return to;
  260. }
  261. @Override
  262. protected SubjectCriteria getFetchCriteria(DSRequest request) {
  263. SubjectCriteria criteria = new SubjectCriteria();
  264. // Pagination
  265. criteria.setPageControl(getPageControl(request));
  266. // Filtering
  267. Integer subjectId = getFilter(request, Field.ID, Integer.class);
  268. criteria.addFilterId(subjectId);
  269. // Always filter out the overlord - mortal users need not know the overlord even exists.
  270. criteria.addFilterFsystem(false);
  271. // Fetching
  272. if (subjectId != null) {
  273. // If we're fetching a single Subject, then fetch the related Set of Roles.
  274. criteria.fetchRoles(true);
  275. }
  276. // TODO: For the list view, use a composite object that will pull the role
  277. // count across the wire. this count will not require permission checks at all.
  278. return criteria;
  279. }
  280. @Override
  281. protected String getSortFieldForColumn(String columnName) {
  282. // this is a calculated field, can't perform server-side sort
  283. if (Field.LDAP.equals(columnName)) {
  284. return null;
  285. }
  286. return super.getSortFieldForColumn(columnName);
  287. }
  288. }