/*
 * Copyright 2016 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.guvnor.common.services.backend.migration;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;

import org.guvnor.common.services.project.model.Project;
import org.guvnor.common.services.project.security.ProjectAction;
import org.guvnor.common.services.project.service.ProjectService;
import org.guvnor.structure.organizationalunit.OrganizationalUnit;
import org.guvnor.structure.organizationalunit.OrganizationalUnitService;
import org.guvnor.structure.repositories.Repository;
import org.guvnor.structure.repositories.RepositoryService;
import org.guvnor.structure.security.OrganizationalUnitAction;
import org.guvnor.structure.security.RepositoryAction;
import org.jboss.errai.security.shared.api.Group;
import org.jboss.errai.security.shared.api.GroupImpl;
import org.uberfire.backend.authz.AuthorizationPolicyStorage;
import org.uberfire.backend.events.AuthorizationPolicyDeployedEvent;
import org.uberfire.security.authz.AuthorizationPolicy;
import org.uberfire.security.authz.Permission;
import org.uberfire.security.authz.PermissionCollection;
import org.uberfire.security.authz.PermissionManager;

/**
 * In previous versions (before the 7 release), the only way to grant access to resources like
 * {@link OrganizationalUnit}, {@link Repository} and {@link Project} was to indicate which groups were able to
 * access a given instance. Those groups were stored as part of the instance persistent status.
 *
 * <p>As of 7 version, the authorization policy is based on permissions. That means is no longer required
 * to keep a list of groups per resource instance. What is required is to define proper permission entries into the
 * active {@link AuthorizationPolicy}</p>
 *
 * <p>This is a utility class which takes care of reading the groups declared for any of the above resource types and
 * creating the necessary permissions so that those resources are protected from user access.</p>
 *
 * <p>The migration procedure is carried out when an {@link AuthorizationPolicyDeployedEvent} is received, which means
 * the application is starting up and deploying the authorization policy for the first time.</p>
 */
@ApplicationScoped
public class ACLMigrationTool {

    private OrganizationalUnitService organizationalUnitService;
    private RepositoryService repositoryService;
    private Instance<ProjectService> projectServices;
    private PermissionManager permissionManager;
    private AuthorizationPolicyStorage authorizationPolicyStorage;
    private Map<String,Group> groupMap = new HashMap<>();

    @Inject
    public ACLMigrationTool(OrganizationalUnitService organizationalUnitService,
                            RepositoryService repositoryService,
                            Instance<ProjectService> projectServices,
                            PermissionManager permissionManager,
                            AuthorizationPolicyStorage authorizationPolicyStorage) {
        this.organizationalUnitService = organizationalUnitService;
        this.repositoryService = repositoryService;
        this.projectServices = projectServices;
        this.permissionManager = permissionManager;
        this.authorizationPolicyStorage = authorizationPolicyStorage;
    }

    public void onDeploy(@Observes AuthorizationPolicyDeployedEvent event) {
        AuthorizationPolicy policy = event.getPolicy();
        migrateOrgUnits(policy);
        migrateRepositories(policy);
        authorizationPolicyStorage.savePolicy(policy);
    }

    private Group getGroup(String groupName) {
        Group group = groupMap.get(groupName);
        if (group == null) {
            group = new GroupImpl(groupName);
            groupMap.put(groupName, group);
        }
        return group;
    }

    public void migrateOrgUnits(AuthorizationPolicy policy) {
        Collection<OrganizationalUnit> itemList = organizationalUnitService.getAllOrganizationalUnits();
        for (OrganizationalUnit item : itemList) {
            Permission p = permissionManager.createPermission(item, OrganizationalUnitAction.READ, true);
            for (String groupName : item.getGroups()) {
                Group group = getGroup(groupName);
                PermissionCollection pc = policy.getPermissions(group);
                pc.add(p);
            }
        }
    }

    public void migrateRepositories(AuthorizationPolicy policy) {
        Collection<Repository> itemList = repositoryService.getAllRepositories();
        for (Repository item : itemList) {
            Permission p = permissionManager.createPermission(item, RepositoryAction.READ, true);
            for (String groupName : item.getGroups()) {
                Group group = getGroup(groupName);
                PermissionCollection pc = policy.getPermissions(group);
                pc.add(p);
            }
            migrateProjects(policy, item);
        }
    }

    public void migrateProjects(AuthorizationPolicy policy, Repository repository) {
        ProjectService projectService = getProjectService();
        if (projectService != null) {
            Collection<Project> itemList = projectService.getAllProjects(repository, "master");
            for (Project item : itemList) {
                Permission p = permissionManager.createPermission(item, ProjectAction.READ, true);
                for (String groupName : item.getGroups()) {
                    Group group = getGroup(groupName);
                    PermissionCollection pc = policy.getPermissions(group);
                    pc.add(p);
                }
            }
        }
    }

    public ProjectService getProjectService() {
        return projectServices.get();
    }
}

@@ -3128,32 +3128,35 @@
 e%3CProjectService
+%3C?%3E
 %3E projectService
@@ -3542,16 +3542,19 @@
 tService
+%3C?%3E
 %3E projec

Fix unsatisfied dependency in ACLMigrationTool in WF10 (from missing type argument). (#330)