class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager, StateListener<State, VirtualMachine.Event, VirtualMachine> {

    @Override
    public UserVm updateVMAffinityGroups(Long vmId, List<Long> affinityGroupIds) {
        // Verify input parameters
        UserVmVO vmInstance = _userVmDao.findById(vmId);
        if (vmInstance == null) {
            throw new InvalidParameterValueException("Unable to find a virtual machine with id " + vmId);
        }

        // Check that the VM is stopped
        if (!vmInstance.getState().equals(State.Stopped)) {
            s_logger.warn("Unable to update affinity groups of the virtual machine " + vmInstance.toString() + " in state " + vmInstance.getState());
            throw new InvalidParameterValueException("Unable update affinity groups of the virtual machine " + vmInstance.toString() + " " + "in state " +
                vmInstance.getState() + "; make sure the virtual machine is stopped and not in an error state before updating.");
        }

        Account caller = CallContext.current().getCallingAccount();
        Account owner = _accountMgr.getAccount(vmInstance.getAccountId());

        // check that the affinity groups exist
        for (Long affinityGroupId : affinityGroupIds) {
            AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId);
            if (ag == null) {
                throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId);
            } else {
                // verify permissions
                _accountMgr.checkAccess(caller, null, true, owner, ag);
                // Root admin has access to both VM and AG by default, but make sure the
                // owner of these entities is same
                if (caller.getId() == Account.ACCOUNT_ID_SYSTEM || _accountMgr.isRootAdmin(caller.getId())) {
                    if (ag.getAccountId() != owner.getAccountId()) {
                        throw new PermissionDeniedException("Affinity Group " + ag + " does not belong to the VM's account");
                    }
                }
            }
        }
        _affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds);
        if (s_logger.isDebugEnabled()) {
            s_logger.debug("Updated VM :" + vmId + " affinity groups to =" + affinityGroupIds);
        }
        // APIResponseHelper will pull out the updated affinitygroups.
        return vmInstance;

    }

}