/*
* RHQ Management Platform
* Copyright (C) 2005-2010 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.coregui.client.admin.roles;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.fields.DataSourceIntegerField;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.types.FieldType;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.authz.Role;
import org.rhq.core.domain.bundle.BundleGroup;
import org.rhq.core.domain.criteria.RoleCriteria;
import org.rhq.core.domain.resource.group.LdapGroup;
import org.rhq.core.domain.resource.group.ResourceGroup;
import org.rhq.core.domain.util.PageList;
import org.rhq.coregui.client.admin.users.UsersDataSource;
import org.rhq.coregui.client.bundle.group.BundleGroupsDataSource;
import org.rhq.coregui.client.gwt.GWTServiceLookup;
import org.rhq.coregui.client.gwt.RoleGWTServiceAsync;
import org.rhq.coregui.client.inventory.groups.ResourceGroupsDataSource;
import org.rhq.coregui.client.util.RPCDataSource;
import org.rhq.coregui.client.util.message.Message;
/**
* A DataSource for RHQ {@link Role role}s.
*
* @author Greg Hinkle
* @author Ian Springer
*/
public class RolesDataSource extends RPCDataSource<Role, RoleCriteria> {
public static abstract class Field {
public static final String ID = "id";
public static final String NAME = "name";
public static final String DESCRIPTION = "description";
public static final String RESOURCE_GROUPS = "resourceGroups";
public static final String BUNDLE_GROUPS = "bundleGroups";
public static final String PERMISSIONS = "permissions";
public static final String SUBJECTS = "subjects";
public static final String LDAP_GROUPS = "ldapGroups";
}
public static abstract class CriteriaField {
public static final String SUBJECT_ID = "subjectId";
}
public static final int ID_SUPERUSER = 1;
private static RolesDataSource INSTANCE;
private RoleGWTServiceAsync roleService = GWTServiceLookup.getRoleService();
public static RolesDataSource getInstance() {
if (INSTANCE == null) {
INSTANCE = new RolesDataSource();
}
return INSTANCE;
}
public static boolean isSystemRoleId(int roleId) {
return (roleId == ID_SUPERUSER);
}
public RolesDataSource() {
super();
List<DataSourceField> fields = addDataSourceFields();
addFields(fields);
}
@Override
protected List<DataSourceField> addDataSourceFields() {
List<DataSourceField> fields = super.addDataSourceFields();
DataSourceIntegerField idDataField = new DataSourceIntegerField(Field.ID, "ID");
idDataField.setPrimaryKey(true);
idDataField.setCanEdit(false);
fields.add(idDataField);
DataSourceTextField nameField = createTextField(Field.NAME, MSG.common_title_name(), 3, 100, true);
fields.add(nameField);
DataSourceTextField descriptionField = createTextField(Field.DESCRIPTION, MSG.common_title_description(), null,
100, false);
fields.add(descriptionField);
DataSourceField resourceGroupsField = new DataSourceField(Field.RESOURCE_GROUPS, FieldType.ANY,
MSG.common_title_resourceGroups());
fields.add(resourceGroupsField);
DataSourceField permissionsField = new DataSourceField(Field.PERMISSIONS, FieldType.ANY,
MSG.common_title_permissions());
fields.add(permissionsField);
DataSourceField subjectsField = new DataSourceField(Field.SUBJECTS, FieldType.ANY,
MSG.datasource_roles_field_subjects());
fields.add(subjectsField);
DataSourceField ldapGroupsField = new DataSourceField(Field.LDAP_GROUPS, FieldType.ANY,
MSG.datasource_roles_field_ldapGroups());
fields.add(ldapGroupsField);
DataSourceField bundleGroupsField = new DataSourceField(Field.BUNDLE_GROUPS, FieldType.ANY,
MSG.common_title_bundleGroups());
fields.add(bundleGroupsField);
return fields;
}
public void executeFetch(final DSRequest request, final DSResponse response, final RoleCriteria criteria) {
roleService.findRolesByCriteria(criteria, new AsyncCallback<PageList<Role>>() {
public void onFailure(Throwable caught) {
sendFailureResponse(request, response, MSG.view_adminRoles_failRoles(), caught);
}
public void onSuccess(PageList<Role> result) {
sendSuccessResponse(request, response, result);
}
});
}
@Override
protected void executeAdd(Record recordToAdd, final DSRequest request, final DSResponse response) {
final Role roleToAdd = copyValues(recordToAdd);
roleService.createRole(roleToAdd, new AsyncCallback<Role>() {
public void onFailure(Throwable caught) {
if (caught.getMessage() != null
&& caught.getMessage().contains("javax.persistence.EntityExistsException")) {
Map<String, String> errorMessages = new HashMap<String, String>();
errorMessages.put(Field.NAME,
MSG.view_adminRoles_failCreateRoleWithExistingName(roleToAdd.getName()));
sendValidationErrorResponse(request, response, errorMessages);
} else {
throw new RuntimeException(caught);
}
}
public void onSuccess(Role addedRole) {
sendSuccessResponse(request, response, addedRole);
}
});
}
@Override
protected void executeUpdate(Record recordToUpdate, Record oldRecord, final DSRequest request,
final DSResponse response) {
Role roleToUpdate = copyValues(recordToUpdate);
final String rolename = roleToUpdate.getName();
roleService.updateRole(roleToUpdate, new AsyncCallback<Role>() {
public void onFailure(Throwable caught) {
sendFailureResponse(request, response, MSG.view_adminRoles_roleUpdateFailed(rolename), caught);
}
public void onSuccess(Role updatedRole) {
sendSuccessResponse(request, response, updatedRole);
}
});
}
@Override
protected void executeRemove(final Record recordToRemove, final DSRequest request, final DSResponse response) {
final Role roleToRemove = copyValues(recordToRemove);
final String rolename = roleToRemove.getName();
roleService.removeRoles(new int[] { roleToRemove.getId() }, new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
sendFailureResponse(request, response, MSG.view_adminRoles_roleDeleteFailed(rolename), caught);
}
public void onSuccess(Void result) {
sendSuccessResponse(request, response, roleToRemove,
new Message(MSG.view_adminRoles_roleDeleted(rolename)));
}
});
}
@SuppressWarnings("unchecked")
public Role copyValues(Record from) {
Role to = new Role();
to.setId(from.getAttributeAsInt(Field.ID));
to.setName(from.getAttributeAsString(Field.NAME));
to.setDescription(from.getAttributeAsString(Field.DESCRIPTION));
Record[] permissionRecords = from.getAttributeAsRecordArray(Field.PERMISSIONS);
Set<Permission> permissions = toPermissionSet(permissionRecords);
to.setPermissions(permissions);
Record[] resourceGroupRecords = from.getAttributeAsRecordArray(Field.RESOURCE_GROUPS);
Set<ResourceGroup> resourceGroups = ResourceGroupsDataSource.getInstance().buildDataObjects(
resourceGroupRecords);
to.setResourceGroups(resourceGroups);
Record[] subjectRecords = from.getAttributeAsRecordArray(Field.SUBJECTS);
Set<Subject> subjects = UsersDataSource.getInstance().buildDataObjects(subjectRecords);
to.setSubjects(subjects);
Record[] ldapGroupRecords = from.getAttributeAsRecordArray(Field.LDAP_GROUPS);
Set<LdapGroup> ldapGroups = new RoleLdapGroupSelector.LdapGroupsDataSource().buildDataObjects(ldapGroupRecords);
to.setLdapGroups(ldapGroups);
Record[] bundleGroupRecords = from.getAttributeAsRecordArray(Field.BUNDLE_GROUPS);
Set<BundleGroup> bundleGroups = BundleGroupsDataSource.getInstance().buildDataObjects(bundleGroupRecords);
to.setBundleGroups(bundleGroups);
return to;
}
public ListGridRecord copyValues(Role sourceRole) {
return copyValues(sourceRole, true);
}
@Override
public ListGridRecord copyValues(Role sourceRole, boolean cascade) {
ListGridRecord targetRecord = new ListGridRecord();
targetRecord.setAttribute(Field.ID, sourceRole.getId());
targetRecord.setAttribute(Field.NAME, sourceRole.getName());
targetRecord.setAttribute(Field.DESCRIPTION, sourceRole.getDescription());
Set<Permission> permissions = sourceRole.getPermissions();
ListGridRecord[] permissionRecords = toRecordArray(permissions);
targetRecord.setAttribute(Field.PERMISSIONS, permissionRecords);
if (cascade) {
Set<ResourceGroup> resourceGroups = sourceRole.getResourceGroups();
ListGridRecord[] resourceGroupRecords = ResourceGroupsDataSource.getInstance().buildRecords(resourceGroups,
false);
targetRecord.setAttribute(Field.RESOURCE_GROUPS, resourceGroupRecords);
Set<Subject> subjects = sourceRole.getSubjects();
ListGridRecord[] subjectRecords = UsersDataSource.getInstance().buildRecords(subjects, false);
targetRecord.setAttribute(Field.SUBJECTS, subjectRecords);
Set<LdapGroup> ldapGroups = sourceRole.getLdapGroups();
ListGridRecord[] ldapGroupRecords = new RoleLdapGroupSelector.LdapGroupsDataSource()
.buildRecords(ldapGroups);
targetRecord.setAttribute(Field.LDAP_GROUPS, ldapGroupRecords);
Set<BundleGroup> bundleGroups = sourceRole.getBundleGroups();
ListGridRecord[] bundleGroupRecords = BundleGroupsDataSource.getInstance()
.buildRecords(bundleGroups, false);
targetRecord.setAttribute(Field.BUNDLE_GROUPS, bundleGroupRecords);
}
return targetRecord;
}
public static Set<Permission> toPermissionSet(Record[] permissionRecords) {
Set<Permission> permissions = new HashSet<Permission>();
// VIEW_RESOURCE is implied, so make sure it's always in the returned Set.
permissions.add(Permission.VIEW_RESOURCE);
for (Record permissionRecord : permissionRecords) {
String permissionName = permissionRecord.getAttribute("name");
Permission permission = Permission.valueOf(permissionName);
permissions.add(permission);
}
return permissions;
}
public static ListGridRecord[] toRecordArray(Set<Permission> permissions) {
ListGridRecord[] permissionRecords = new ListGridRecord[permissions.size()];
int index = 0;
for (Permission permission : permissions) {
ListGridRecord permissionRecord = new ListGridRecord();
permissionRecord.setAttribute("name", permission.name());
permissionRecords[index++] = permissionRecord;
}
return permissionRecords;
}
protected RoleCriteria getFetchCriteria(DSRequest request) {
RoleCriteria criteria = new RoleCriteria();
// Filtering
Integer id = getFilter(request, Field.ID, Integer.class);
criteria.addFilterId(id);
Integer subjectId = getFilter(request, CriteriaField.SUBJECT_ID, Integer.class);
if (subjectId != null) {
criteria.addFilterSubjectId(subjectId);
}
// Fetching
criteria.fetchPermissions(true);
if (id != null) {
// If we're fetching a single Role, then fetch all the related Sets.
criteria.fetchSubjects(true);
criteria.fetchResourceGroups(true);
criteria.fetchLdapGroups(true);
criteria.fetchBundleGroups(true);
}
// TODO: instead of fetching subjects and resource groups, use a composite object that will pull the subject
// and resource group count across the wire. these counts will not required permission checks at all.
return criteria;
}
}