/* * * RHQ Sync Tool * Copyright (C) 2012-2013 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 Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * 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 and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package org.jboss.rhq.sync.tool.actions.impl.impex.templates; import static org.jboss.rhq.sync.tool.actions.impl.impex.RoleSerializer.loadJsonRolesCollections; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.jboss.rhq.sync.tool.BaseRemote; import org.jboss.rhq.sync.tool.LoginConfiguration; import org.jboss.rhq.sync.tool.actions.JonActionResult.JonActionResultType; import org.jboss.rhq.sync.tool.actions.impl.AbstractJONImportAction; import org.jboss.rhq.sync.tool.query.SubjectsAndRolesQueryImpl; import org.jboss.rhq.sync.tool.util.DomainCollectionsUtils; import org.jboss.rhq.sync.tool.util.FileUtils; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.authz.Role; /** * @author Romain PELISSE - <belaran@redhat.com> * */ public class RolesImportAction extends AbstractJONImportAction<Collection<Role>> implements ImportStrategy<Role> { private static Logger logger = Logger.getLogger(RolesImportAction.class); private ImportStrategy<Subject> subjectImporter = new SubjectImporter(); /** * @param loginConfiguration * @param baseRemote */ public RolesImportAction(LoginConfiguration loginConfiguration, BaseRemote baseRemote) { super(loginConfiguration, baseRemote); } /** * <p>Default constructor - inherits remote login and base</p> */ public RolesImportAction() {} @Override protected Collection<Role> loadFromFile(String filename) { if ( logger.isDebugEnabled() ) logger.debug("invoked with " + filename); return loadJsonRolesCollections(FileUtils.read(filename)); } @Override protected JonActionResultType doImport(Collection<Role> roles) { long startTime = System.currentTimeMillis(); if ( logger.isDebugEnabled() ) logger.debug("1. Regroups all users of all roles, index by their username."); // *BE CAREFUL* Huge simplification is done here, we assume // that 'username' are UNIQUES. Map<String /*username*/, Subject> rolesSubjects = DomainCollectionsUtils.indexSubjectsFromRolesByName(roles); if ( logger.isDebugEnabled() ) logger.debug("2. Fetch all \"existing user\" from the previous list (one remote call, hopefully)."); Map<String, Subject> existingSubject = subjectImporter.retrieveExistingItems(rolesSubjects); if ( logger.isDebugEnabled() ) logger.debug("3. Create missing Subjects (one remote call) - if any."); Map<String,Subject> createdSubjects = subjectImporter.importItem(subjectImporter.determineItemsToCreate(rolesSubjects,existingSubject)); Map<String,Role> providedRoles = DomainCollectionsUtils.indexRoleByName(roles); Map<String,Role> existingRoles = retrieveExistingItems(providedRoles); Map<String,Role> unexistingRoles = determineItemsToCreate(providedRoles,existingRoles); Set<Role> addedRoles = new HashSet<Role>(roles.size()); int id = 0; for ( Role role : roles ) { if ( logger.isDebugEnabled() ) logger.debug("4.(" + id + ") Create Role " + role.getName() + " without subjects (one remote call, could be concurrent to the previous remote call, but most likely not worth it)"); // Removes Subjects as having subjects in the role leads to a transport error ! Collection<Subject> subjects = DomainCollectionsUtils.extractsSubjectsFromRole(role); // create role and fetch id back if ( unexistingRoles.containsKey(role.getName()) && checkIfRoleCanBeAdded(role) ) { role.setId(0); role = new SubjectsAndRolesQueryImpl().addRole(role); } else { if ( ! existingRoles.containsKey(role.getName())) { throw new IllegalStateException("Role " + role.getName() + "is neither existing, neither to create..."); } else role = existingRoles.get(role.getName()); } addedRoles.add(role); if ( logger.isDebugEnabled() ) logger.debug("5. (" + id++ + ") Add subjects to appropriate role"); if ( ! subjects.isEmpty() ) { new SubjectsAndRolesQueryImpl().addSubjectsToRole(role, subjectToAlter(subjects, existingSubject, createdSubjects)); } } logger.warn("Overall import operation execution time:" + (System.currentTimeMillis() - startTime) + "ms."); if ( logger.isDebugEnabled() ) { logger.debug("The following roles have been successfully imported:"); for ( Role role : addedRoles ) logger.debug(role); } return JonActionResultType.SUCCESS; } //FIXME: Cut'n'paste from org.rhq.enterprise.server.authz.AuthorizationManagerBean (sadly not public) // import and use proper bean ? private static final int SUBJECT_ID_OVERLORD = 1; private static final int SUBJECT_ID_RHQADMIN = 2; private boolean subjectCanBeAltered(Subject subjectToAlter) { return subjectToAlter.getId() != SUBJECT_ID_OVERLORD && subjectToAlter.getId() != SUBJECT_ID_RHQADMIN; } private boolean checkIfRoleCanBeAdded(Role role) { boolean fsystemRole = role.getFsystem(); if ( fsystemRole ) logger.warn("Role " + role.getName() + " is a system role and can't be imported"); return ! fsystemRole; } private Set<Subject> subjectToAlter(Collection<Subject> subjects, Map<String, Subject> existingSubject,Map<String, Subject> createdSubjects) { Set<Subject> subjectsToAlter = new HashSet<Subject>(subjects.size()); for ( Subject subject : subjects ) { Subject subjectToAlter = DomainCollectionsUtils.findSubject(subject, existingSubject, createdSubjects); if ( subjectCanBeAltered(subjectToAlter) ) subjectsToAlter.add(subjectToAlter); } return subjectsToAlter; } @Override public Map<String, Role> retrieveExistingItems( Map<String, Role> providedRoles) { Map<String,Role> existingRolesCollection = new HashMap<String,Role>(0); // FIXME: find a away to do this search in one request for ( Role role : providedRoles.values() ) { existingRolesCollection.putAll(DomainCollectionsUtils.indexRoleByName(new SubjectsAndRolesQueryImpl().findRolesByNames(role))); } return existingRolesCollection; } @Override public Map<String, Role> determineItemsToCreate( Map<String, Role> providedItems, Map<String, Role> existingRoles) { return DomainCollectionsUtils.removeExistingItemsFromProvided(existingRoles,providedItems); } @Override public Map<String, Role> importItem(Map<String, Role> rolesToCreate) { throw new UnsupportedOperationException("Not implemented."); } }