com.redhat.rhn.frontend.xmlrpc.activationkey.ActivationKeyHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.rhn.frontend.xmlrpc.activationkey.ActivationKeyHandler.java

Source

/**
 * Copyright (c) 2009--2014 Red Hat, Inc.
 *
 * This software is licensed to you under the GNU General Public License,
 * version 2 (GPLv2). There is NO WARRANTY for this software, express or
 * implied, including the implied warranties of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
 * along with this software; if not, see
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 * Red Hat trademarks are not licensed under GPLv2. No permission is
 * granted to use or replicate Red Hat trademarks that are incorporated
 * in this software or its documentation.
 */
package com.redhat.rhn.frontend.xmlrpc.activationkey;

import com.redhat.rhn.FaultException;
import com.redhat.rhn.common.hibernate.LookupException;
import com.redhat.rhn.common.validator.ValidatorError;
import com.redhat.rhn.common.validator.ValidatorException;
import com.redhat.rhn.common.validator.ValidatorResult;
import com.redhat.rhn.domain.channel.Channel;
import com.redhat.rhn.domain.config.ConfigChannel;
import com.redhat.rhn.domain.config.ConfigChannelListProcessor;
import com.redhat.rhn.domain.rhnpackage.PackageArch;
import com.redhat.rhn.domain.rhnpackage.PackageFactory;
import com.redhat.rhn.domain.rhnpackage.PackageName;
import com.redhat.rhn.domain.server.ManagedServerGroup;
import com.redhat.rhn.domain.server.Server;
import com.redhat.rhn.domain.server.ServerGroup;
import com.redhat.rhn.domain.server.ServerGroupType;
import com.redhat.rhn.domain.token.ActivationKey;
import com.redhat.rhn.domain.token.ActivationKeyFactory;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.frontend.struts.RhnValidationHelper;
import com.redhat.rhn.frontend.xmlrpc.BaseHandler;
import com.redhat.rhn.frontend.xmlrpc.InvalidArgsException;
import com.redhat.rhn.frontend.xmlrpc.InvalidChannelException;
import com.redhat.rhn.frontend.xmlrpc.InvalidPackageException;
import com.redhat.rhn.frontend.xmlrpc.InvalidServerGroupException;
import com.redhat.rhn.frontend.xmlrpc.MissingEntitlementException;
import com.redhat.rhn.frontend.xmlrpc.ValidationException;
import com.redhat.rhn.frontend.xmlrpc.configchannel.XmlRpcConfigChannelHelper;
import com.redhat.rhn.manager.channel.ChannelManager;
import com.redhat.rhn.manager.rhnpackage.PackageManager;
import com.redhat.rhn.manager.system.ServerGroupManager;
import com.redhat.rhn.manager.token.ActivationKeyCloneCommand;
import com.redhat.rhn.manager.token.ActivationKeyManager;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.NonUniqueObjectException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * ActivationKeyHandler
 *
 * @version $Rev$
 *
 * @xmlrpc.namespace activationkey
 * @xmlrpc.doc Contains methods to access common activation key functions
 * available from the web interface.
 */
public class ActivationKeyHandler extends BaseHandler {

    private static Logger log = Logger.getLogger(ActivationKeyHandler.class);

    private static final String VALIDATION_XSD = "/com/redhat/rhn/frontend/action/token/validation/activationKeyForm.xsd";

    /**
     * Creates a new activation key.
     * @param loggedInUser The current user
     * @param key Key for the activation key, or empty string to have one
     * autogenerated.
     * @param description A note or description.
     * @param baseChannelLabel label of this key's base channel.
     * @param usageLimit Usage limit for this key.
     * @param entitlements List of string entitlement labels for the activation key.
     * @param universalDefault Whether or not this key should be set as the
     * default for the user's organization.
     * @return Key of the newly created activation key.
     * @throws FaultException A FaultException is thrown if the loggedInUser
     * doesn't have permissions to create new activation keys.
     *
     * @xmlrpc.doc Create a new activation key.
     * The activation key parameter passed
     * in will be prefixed with the organization ID, and this value will be
     * returned from the create call.
     *
     * Eg. If the caller passes in the key "foo" and belong to an organization with
     * the ID 100, the actual activation key will be "100-foo".
     *
     * This call allows for the setting of a usage limit on this activation key.
     * If unlimited usage is desired see the similarly named API method with no
     * usage limit argument.
     *
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param_desc("string", "key",
     * "Leave empty to have new key autogenerated.")
     * @xmlrpc.param #param("string", "description")
     * @xmlrpc.param #param_desc("string", "baseChannelLabel", "Leave empty to accept
     * default.")
     * @xmlrpc.param #param_desc("int", "usageLimit", "If unlimited usage is desired,
     * use the create API that does not include the parameter.")
     * @xmlrpc.param #array_desc("string", "Add-on entitlement label to associate with the
     * key.")
     *   #options()
     *     #item("provisioning_entitled")
     *     #item("virtualization_host")
     *     #item("virtualization_host_platform")
     *   #options_end()
     * #array_desc_end()
     * @xmlrpc.param #param("boolean", "universalDefault")
     * @xmlrpc.returntype string - The new activation key.
     */
    public String create(User loggedInUser, String key, String description, String baseChannelLabel,
            Integer usageLimit, List entitlements, Boolean universalDefault) throws FaultException {

        Channel baseChannel = null;
        try {
            if (!StringUtils.isBlank(baseChannelLabel)) {
                baseChannel = ChannelManager.lookupByLabelAndUser(baseChannelLabel, loggedInUser);
                // Verify the channel given is actually a base channel:
                if (!baseChannel.isBaseChannel()) {
                    throw new InvalidChannelException(baseChannel.getName() + " is not a base channel.");
                }
            }
        } catch (LookupException e) {
            throw new InvalidChannelException(e);
        }

        // Validate the input parameters.  We will use the RhnValidationHelper
        // for this which is also used to validate input if user entered it from the UI.
        Map<String, String> values = new HashMap<String, String>();
        values.put("description", description);
        values.put("key", key);
        if (usageLimit != null) {
            values.put("usageLimit", usageLimit.toString());
        }

        ValidatorResult result = RhnValidationHelper.validate(this.getClass(), values,
                new LinkedList<String>(values.keySet()), VALIDATION_XSD);

        if (!result.isEmpty()) {
            log.error("Validation errors:");
            for (ValidatorError error : result.getErrors()) {
                log.error("   " + error.getMessage());
            }
            // Multiple errors could return here, but we'll have to just throw an
            // exception for the first one and return that to the user.
            ValidatorError e = result.getErrors().get(0);
            throw new ValidationException(e.getMessage());
        }

        try {
            ActivationKeyManager akm = ActivationKeyManager.getInstance();
            // validate the entitlements BEFORE creating a key
            akm.validateAddOnEntitlements(entitlements, true);

            Long limit = null;
            if (usageLimit != null && Long.valueOf(usageLimit) >= 0) {
                limit = Long.valueOf(usageLimit);
            }

            ActivationKey newKey = akm.createNewActivationKey(loggedInUser, key, description, limit, baseChannel,
                    universalDefault.booleanValue());

            akm.addEntitlements(newKey, entitlements);

            return newKey.getKey();
        } catch (ValidatorException ve) {
            throw FaultException.create(1091, "activationkey", ve.getResult());
        } catch (NonUniqueObjectException e) {
            throw new ActivationKeyAlreadyExistsException();
        }
    }

    /**
     * Clones activation key
     * @param loggedInUser The current user
     * @param key Actication Key to be cloned
     * @param cloneDescription Description for the new activation key.
     * @return Key of the newly created activation key.
     * @throws FaultException A FaultException is thrown if the loggedInUser
     * doesn't have permissions to create new activation keys.
     * @xmlrpc.doc Clone an existing activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param_desc("string", "key", "Key to be cloned.")
     * @xmlrpc.param #param_desc("string", "cloneDescription",
     * "Description of the cloned key.")
     * @xmlrpc.returntype string - The new activation key.
     */
    public String clone(User loggedInUser, String key, String cloneDescription) throws FaultException {
        ActivationKeyCloneCommand cak = new ActivationKeyCloneCommand(loggedInUser, key, cloneDescription);
        return cak.getclonedkey();
    }

    /**
     * Creates a new activation key with unlimited usage..
     * @param loggedInUser The current user
     * @param key Key for the activation key, or empty string to have one
     * autogenerated.
     * @param description A note or description.
     * @param baseChannelLabel label of this key's base channel.
     * @param entitlements List of string entitlement labels for the activation key.
     * @param universalDefault Whether or not this key should be set as the
     * default for the user's organization.
     * @return Key of the newly created activation key.
     * @throws FaultException A FaultException is thrown if the loggedInUser
     * doesn't have permissions to create new activation keys.
     *
     * @xmlrpc.doc Create a new activation key with unlimited usage.
     * The activation key parameter passed
     * in will be prefixed with the organization ID, and this value will be
     * returned from the create call.
     *
     * Eg. If the caller passes in the key "foo" and belong to an organization with
     * the ID 100, the actual activation key will be "100-foo".
     *
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param_desc("string", "key",
     * "Leave empty to have new key autogenerated.")
     * @xmlrpc.param #param("string", "description")
     * @xmlrpc.param #param_desc("string", "baseChannelLabel", "Leave empty to accept
     * default.")
     * @xmlrpc.param #array_desc("string", "Add-on entitlement label to associate with the
     * key.")
     *   #options()
     *     #item("provisioning_entitled")
     *     #item("virtualization_host")
     *     #item("virtualization_host_platform")
     *   #options_end()
     * #array_desc_end()
     * @xmlrpc.param #param("boolean", "universalDefault")
     * @xmlrpc.returntype string - The new activation key.
     */
    public String create(User loggedInUser, String key, String description, String baseChannelLabel,
            List entitlements, Boolean universalDefault) throws FaultException {

        return create(loggedInUser, key, description, baseChannelLabel, null, entitlements, universalDefault);
    }

    /**
     * Deletes an activation key.
     * @param loggedInUser The current user
     * @param key Key for the activation key, or empty string to have one
     * autogenerated.
     * @return Key of the newly created activation key.
     * @throws IllegalArgumentException if the loggedInUser
     * doesn't have permissions to create new activation keys.
     *
     * @xmlrpc.doc Delete an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.returntype #return_int_success()
     */
    public int delete(User loggedInUser, String key) {
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        ActivationKeyManager.getInstance().remove(activationKey, loggedInUser);
        return 1;
    }

    /**
     * Set activation key details.
     * @param loggedInUser The current user
     * @param key The activation key to be modified
     * @param details Map of new details. (contents optional)
     * @return 1 if edit was successful, exception thrown otherwise.
     * @throws FaultException Thrown if the user does not have the activation
     * key admin role, if the base channel given does not exist, or if it
     * actually is not a base channel.
     *
     * @xmlrpc.doc Update the details of an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #struct("activation key")
     *   #prop_desc("string", "description", "optional")
     *   #prop_desc("string", "base_channel_label", "optional -
     *   to set default base channel set to empty string or 'none'")
     *   #prop_desc("int", "usage_limit", "optional")
     *   #prop_desc("boolean", "unlimited_usage_limit", "Set true
     *   for unlimited usage and to override usage_limit")
     *   #prop_desc("boolean", "universal_default", "optional")
     *   #prop_desc("boolean", "disabled", "optional")
     * #struct_end()
     * @xmlrpc.returntype #return_int_success()
     */
    public int setDetails(User loggedInUser, String key, Map details) throws FaultException {

        // confirm that the user only provided valid keys in the map
        Set<String> validKeys = new HashSet<String>();
        validKeys.add("description");
        validKeys.add("base_channel_label");
        validKeys.add("usage_limit");
        validKeys.add("unlimited_usage_limit");
        validKeys.add("universal_default");
        validKeys.add("disabled");
        validateMap(validKeys, details);

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey aKey = lookupKey(key, loggedInUser);

        // Keep base channel as it is unless explicitly changed:
        Channel baseChannel = aKey.getBaseChannel();
        if (details.containsKey("base_channel_label")) {
            String baseChannelLabel = (String) details.get("base_channel_label");
            if (StringUtils.isEmpty(baseChannelLabel) || baseChannelLabel.equals("none")) {
                baseChannel = null;
            } else {
                try {
                    baseChannel = ChannelManager.lookupByLabelAndUser(baseChannelLabel, loggedInUser);
                } catch (LookupException e) {
                    throw new InvalidChannelException(e);
                }

                // Verify the channel given is actually a base channel:
                if (!baseChannel.isBaseChannel()) {
                    throw new InvalidChannelException(baseChannel.getName() + " is not a base channel.");
                }
            }
        }

        String description = null;
        if (details.containsKey("description")) {
            description = (String) details.get("description");
        }

        if (details.containsKey("usage_limit")) {
            Long usageLimit = new Long(((Integer) details.get("usage_limit")).longValue());
            aKey.setUsageLimit(usageLimit);
        }

        // Check if we need to override the usage_limit and set to unlimited:
        if (details.containsKey("unlimited_usage_limit")) {
            Boolean unlimited = (Boolean) details.get("unlimited_usage_limit");
            if (unlimited.booleanValue()) {
                aKey.setUsageLimit(null);
            }
        }

        if (details.containsKey("universal_default")) {
            Boolean universalDefault = (Boolean) details.get("universal_default");
            aKey.setUniversalDefault(universalDefault.booleanValue());
        }

        if (details.containsKey("disabled")) {
            aKey.setDisabled((Boolean) details.get("disabled"));
        }

        manager.update(aKey, description, baseChannel);
        return 1;
    }

    /**
     * Return a struct of activation key details.
     * @param loggedInUser The current user
     * @param key The activation key to be modified
     * @return Map representation of the activation key
     * @since 10.2
     *
     * @xmlrpc.doc Lookup an activation key's details.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.returntype $ActivationKeySerializer
     */
    public ActivationKey getDetails(User loggedInUser, String key) {
        ActivationKey aKey = lookupKey(key, loggedInUser);
        return aKey;
    }

    /**
     * Add entitlements to an activation key. Currently only add-on entitlements are
     * permitted. (provisioning_entitled, virtualization_host,
     * virtualization_host_platform)
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon.
     * @param entitlements List of string entitlement labels to be added.
     * @return 1 on success, exception thrown otherwise.
     *
     * @xmlrpc.doc Add entitlements to an activation key. Currently only add-on
     * entitlements are permitted. (provisioning_entitled,
     * virtualization_host, virtualization_host_platform)
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_desc("string", "entitlement label")
     *   #options()
     *     #item("provisioning_entitled")
     *     #item("virtualization_host")
     *     #item("virtualization_host_platform")
     *   #options_end()
     * #array_desc_end()
     * @xmlrpc.returntype #return_int_success()
     */
    public int addEntitlements(User loggedInUser, String key, List entitlements) {
        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        manager.addEntitlements(activationKey, entitlements);
        return 1;
    }

    /**
     * Remove entitlements from an activation key. Currently only add-on entitlements are
     * permitted. (provisioning_entitled, virtualization_host,
     * virtualization_host_platform)
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon.
     * @param entitlements List of string entitlement labels to be removed.
     * @return 1 on success, exception thrown otherwise.
     *
     * @xmlrpc.doc Remove entitlements (by label) from an activation key. Currently
     * only add-on entitlements are permitted. (
     * provisioning_entitled, virtualization_host, virtualization_host_platform)
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_desc("string", "entitlement label")
     *   #options()
     *     #item("provisioning_entitled")
     *     #item("virtualization_host")
     *     #item("virtualization_host_platform")
     *   #options_end()
     * #array_desc_end()
     * @xmlrpc.returntype #return_int_success()
     */
    public int removeEntitlements(User loggedInUser, String key, List entitlements) {
        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        manager.removeEntitlements(activationKey, entitlements);
        return 1;
    }

    /**
     * Add a child channel to an activation key.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon
     * @param childChannelLabels List of child channel labels to be added to this
     *          activation key
     * @return 1 on success, exception thrown otherwise
     *
     * @xmlrpc.doc Add child channels to an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_single("string", "childChannelLabel")
     * @xmlrpc.returntype #return_int_success()
     */
    public int addChildChannels(User loggedInUser, String key, List childChannelLabels) {

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        for (Iterator it = childChannelLabels.iterator(); it.hasNext();) {
            String childChannelLabel = (String) it.next();

            Channel childChannel = null;
            try {
                childChannel = ChannelManager.lookupByLabelAndUser(childChannelLabel, loggedInUser);
            } catch (LookupException e) {
                throw new InvalidChannelException(e);
            }

            // Verify the channel given is actually a child channel:
            if (childChannel.isBaseChannel()) {
                throw new InvalidChannelException(childChannel.getName() + " is not a child channel.");
            }

            // Verify that, *IF* this AK specifies a base-channel, then the proposed
            // child is a child of *that* base channel
            Channel base = activationKey.getBaseChannel();
            if (base != null && !base.equals(childChannel.getParentChannel())) {
                throw new InvalidChannelException(childChannel.getName() + " is not a child channel of parent "
                        + base.getName() + " which is already used by this key");
            }

            manager.addChannel(activationKey, childChannel);
        }

        return 1;
    }

    /**
     * Remove a child channel from an activation key.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon
     * @param childChannelLabels List of child channel labels to be removed
     *    from this activation key
     * @return 1 on success, exception thrown otherwise
     *
     * @xmlrpc.doc Remove child channels from an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_single("string", "childChannelLabel")
     * @xmlrpc.returntype #return_int_success()
     */
    public int removeChildChannels(User loggedInUser, String key, List childChannelLabels) {

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);

        for (Iterator it = childChannelLabels.iterator(); it.hasNext();) {
            String childChannelLabel = (String) it.next();

            Channel childChannel = null;
            try {
                childChannel = ChannelManager.lookupByLabelAndUser(childChannelLabel, loggedInUser);
            } catch (LookupException e) {
                throw new InvalidChannelException(e);
            }

            // Verify the channel given is actually a child channel:
            if (childChannel.isBaseChannel()) {
                throw new InvalidChannelException(childChannel.getName() + " is not a child channel.");
            }

            manager.removeChannel(activationKey, childChannel);
        }

        return 1;
    }

    /**
     * Add server groups to an activation key.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon.
     * @param serverGroupIds List of server group IDs to be added to this activation key.
     * @return 1 on success, exception thrown otherwise.
     *
     * @xmlrpc.doc Add server groups to an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_single("int", "serverGroupId")
     * @xmlrpc.returntype #return_int_success()
     */
    public int addServerGroups(User loggedInUser, String key, List serverGroupIds) {

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);

        for (Iterator it = serverGroupIds.iterator(); it.hasNext();) {
            Number serverGroupId = (Number) it.next();

            ManagedServerGroup group = null;
            try {
                group = ServerGroupManager.getInstance().lookup(new Long(serverGroupId.longValue()), loggedInUser);
            } catch (LookupException e) {
                throw new InvalidServerGroupException(e);
            }

            manager.addServerGroup(activationKey, group);
        }

        return 1;
    }

    /**
     * Remove server groups from an activation key.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon
     * @param serverGroupIds List of server group IDs to be removed from this activation key
     * @return 1 on success, exception thrown otherwise
     *
     * @xmlrpc.doc Remove server groups from an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_single("int", "serverGroupId")
     * @xmlrpc.returntype #return_int_success()
     */
    public int removeServerGroups(User loggedInUser, String key, List serverGroupIds) {

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);

        for (Iterator it = serverGroupIds.iterator(); it.hasNext();) {
            Integer serverGroupId = (Integer) it.next();

            ServerGroup group = null;
            try {
                group = ServerGroupManager.getInstance().lookup(new Long(serverGroupId.longValue()), loggedInUser);
            } catch (LookupException e) {
                throw new InvalidServerGroupException(e);
            }

            manager.removeServerGroup(activationKey, group);
        }
        return 1;
    }

    /**
     * Validate that an activation key has a particular entitlement.
     *
     * @param key
     * @param entitlement
     */
    private void validateKeyHasEntitlement(ActivationKey key, String entitlement) {
        for (Iterator it = key.getEntitlements().iterator(); it.hasNext();) {
            ServerGroupType type = (ServerGroupType) it.next();
            if (type.getLabel().equals(entitlement)) {
                return;
            }
        }
        throw new MissingEntitlementException(entitlement);
    }

    /**
     * Add packages to an activation key using package name only.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon
     * @param packageNames List of package names to be added to this activation key
     * @return 1 on success, exception thrown otherwise.
     * @deprecated being replaced by addPackages(string sessionKey, string key,
     * array[packages])
     * @since 10.2
     *
     * @xmlrpc.doc Add packages to an activation key using package name only.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_single("string", "packageName")
     * @xmlrpc.returntype #return_int_success()
     */
    @Deprecated
    public int addPackageNames(User loggedInUser, String key, List packageNames) {

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        validateKeyHasEntitlement(activationKey, "provisioning_entitled");

        for (Iterator it = packageNames.iterator(); it.hasNext();) {
            String name = (String) it.next();
            PackageName packageName = PackageFactory.lookupOrCreatePackageByName(name);
            manager.addPackage(activationKey, packageName, null);
        }
        return 1;
    }

    /**
     * Remove package names from an activation key.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon
     * @param packageNames List of package names to be removed from this activation key
     * @return 1 on success, exception thrown otherwise
     * @deprecated being replaced by removePackages(string sessionKey, string key,
     * array[packages])
     * @since 10.2
     *
     * @xmlrpc.doc Remove package names from an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param #array_single("string", "packageName")
     * @xmlrpc.returntype #return_int_success()
     */
    @Deprecated
    public int removePackageNames(User loggedInUser, String key, List packageNames) {

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        validateKeyHasEntitlement(activationKey, "provisioning_entitled");

        for (Iterator it = packageNames.iterator(); it.hasNext();) {
            String name = (String) it.next();

            PackageName packageName = null;
            try {
                packageName = PackageManager.lookupPackageName(name);
            } catch (LookupException e) {
                throw new InvalidPackageException(packageName.getName(), e);
            }
            manager.removePackage(activationKey, packageName, null);
        }
        return 1;
    }

    /**
     * Add packages to an activation key.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon
     * @param packages List of packages to be added to this activation key
     * @return 1 on success, exception thrown otherwise.
     *
     * @xmlrpc.doc Add packages to an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param
     *   #array()
     *      #struct("packages")
     *          #prop_desc("string", "name", "Package name")
     *          #prop_desc("string", "arch", "Arch label - Optional")
     *     #struct_end()
     *   #array_end()
     * @xmlrpc.returntype #return_int_success()
     */
    public int addPackages(User loggedInUser, String key, List<Map<String, String>> packages) {

        // confirm that the user only provided valid keys in the map
        Set<String> validKeys = new HashSet<String>();
        validKeys.add("name");
        validKeys.add("arch");
        for (Map<String, String> pkg : packages) {
            validateMap(validKeys, pkg);
        }

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        validateKeyHasEntitlement(activationKey, "provisioning_entitled");

        String name = null;
        String arch = null;
        for (Map<String, String> pkg : packages) {
            name = pkg.get("name");
            if (name.contains(" ")) {
                throw new InvalidArgsException("More than one package names are specified.");
            }
            PackageName packageName = PackageFactory.lookupOrCreatePackageByName(name);

            arch = pkg.get("arch");
            PackageArch packageArch = PackageFactory.lookupPackageArchByLabel(arch);

            manager.addPackage(activationKey, packageName, packageArch);
            ActivationKeyFactory.save(activationKey);
        }
        return 1;
    }

    /**
     * Remove packages from an activation key.
     *
     * @param loggedInUser The current user
     * @param key The activation key to act upon
     * @param packages List of packages to be removed from this activation key
     * @return 1 on success, exception thrown otherwise
     *
     * @xmlrpc.doc Remove package names from an activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.param
     *   #array()
     *      #struct("packages")
     *          #prop_desc("string", "name", "Package name")
     *          #prop_desc("string", "arch", "Arch label - Optional")
     *     #struct_end()
     *   #array_end()
     * @xmlrpc.returntype #return_int_success()
     */
    public int removePackages(User loggedInUser, String key, List<Map<String, String>> packages) {

        // confirm that the user only provided valid keys in the map
        Set<String> validKeys = new HashSet<String>();
        validKeys.add("name");
        validKeys.add("arch");
        for (Map<String, String> pkg : packages) {
            validateMap(validKeys, pkg);
        }

        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        validateKeyHasEntitlement(activationKey, "provisioning_entitled");

        String name = null;
        String arch = null;
        for (Map<String, String> pkg : packages) {
            name = pkg.get("name");
            PackageName packageName = PackageFactory.lookupOrCreatePackageByName(name);

            arch = pkg.get("arch");
            PackageArch packageArch = PackageFactory.lookupPackageArchByLabel(arch);

            manager.removePackage(activationKey, packageName, packageArch);
        }
        return 1;
    }

    /**
     * Return a list of activation key structs that are visible to the requesting user.
     * @param loggedInUser The current user
     * @return List of map representations of activation keys
     * @since 10.2
     *
     * @xmlrpc.doc List activation keys that are visible to the
     * user.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.returntype
     *   #array()
     *     $ActivationKeySerializer
     *   #array_end()
     */
    public List<ActivationKey> listActivationKeys(User loggedInUser) {
        List<ActivationKey> result = new ArrayList<ActivationKey>();
        ActivationKeyManager manager = ActivationKeyManager.getInstance();
        for (ActivationKey key : manager.findAll(loggedInUser)) {
            try {
                manager.validateCredentials(loggedInUser, null, key);
            } catch (LookupException e) {
                continue; // skip keys in this org that this user can't see
            }
            result.add(key);
        }

        return result;
    }

    /**
     * Return a list of systems activated with the activation key provided.
     * @param loggedInUser The current user
     * @param key The activation key
     * @return List of map representations of systems.
     *
     * @xmlrpc.doc List the systems activated with the key provided.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.returntype
     *   #array()
     *       #struct("system structure")
     *           #prop_desc("int", "id", "System id")
     *           #prop("string", "hostname")
     *           #prop_desc("dateTime.iso8601",  "last_checkin", "Last time server
     *               successfully checked in")
     *       #struct_end()
     *   #array_end()
     */
    public Object[] listActivatedSystems(User loggedInUser, String key) {
        ActivationKey activationKey = lookupKey(key, loggedInUser);

        List<Server> servers = new LinkedList<Server>(activationKey.getToken().getActivatedServers());

        List<Object> returnList = new ArrayList<Object>();

        // For this API, we don't need to pass back to the user all of the
        // information that is defined for a "Server" as would be returned
        // by the ServerSerializer; therefore, we'll just pull a few key
        // pieces of information.
        for (Server server : servers) {
            Map<String, Object> system = new HashMap<String, Object>();

            system.put("id", server.getId());
            system.put("hostname", server.getHostname());
            system.put("last_checkin", server.getLastCheckin());
            returnList.add(system);
        }
        return returnList.toArray();
    }

    private ActivationKey lookupKey(String key, User user) {
        return XmlRpcActivationKeysHelper.getInstance().lookupKey(user, key);
    }

    /**
     * Returns a list of  config channel structs that are  associated
     * to a given activation key.
     *
     * @param loggedInUser The current user
     * @param key the activation key
     * @return list of config channel strutcs
     *
     *
     * @xmlrpc.doc List configuration channels
     * associated to an activation key.
     *
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.returntype
     *   #array()
     *     $ConfigChannelSerializer
     *   #array_end()
     */
    public List listConfigChannels(User loggedInUser, String key) {
        ActivationKey activationKey = lookupKey(key, loggedInUser);
        return activationKey.getConfigChannelsFor(loggedInUser);
    }

    /**
     * replaces the existing set of config channels for a given activation key.
     * Note: it ranks these channels according to the array order of
     * configChannelIds method parameter
     * @param loggedInUser The current user
     * @param keys a lsit of  activation keys.
     * @param configChannelLabels sets channels labels
     * @return 1 on success 0 on failure
     *
     * @xmlrpc.doc Replace the existing set of
     * configuration channels on the given activation keys.
     * Channels are ranked by their order in the array.
     * @xmlrpc.param #param("string", "sessionKey ")
     * @xmlrpc.param #array_single("string", "activationKey")
     * @xmlrpc.param #array_single("string", "configChannelLabel")
     * @xmlrpc.returntype #return_int_success()
     */
    public int setConfigChannels(User loggedInUser, List<String> keys, List<String> configChannelLabels) {
        XmlRpcActivationKeysHelper helper = XmlRpcActivationKeysHelper.getInstance();
        List<ActivationKey> activationKeys = helper.lookupKeys(loggedInUser, keys);
        XmlRpcConfigChannelHelper configHelper = XmlRpcConfigChannelHelper.getInstance();
        List channels = configHelper.lookupGlobals(loggedInUser, configChannelLabels);
        ConfigChannelListProcessor proc = new ConfigChannelListProcessor();
        for (ActivationKey activationKey : activationKeys) {
            proc.replace(activationKey.getConfigChannelsFor(loggedInUser), channels);
        }
        return 1;
    }

    /**
     * Given a list of activation keys and configuration channels,
     * this method inserts the configuration channels to either the top or
     * the bottom (whichever you specify) of an activation key's
     * configuration channels list. The ordering of the configuration channels
     * provided in the add list is maintained while adding.
     * If one of the configuration channels in the 'add' list
     * already exists in an activation key, the
     * configuration  channel will be re-ranked to the appropriate place.
     * @param loggedInUser The current user
     * @param keys the list of activation keys.
     * @param configChannelLabels set of configuration channels labels
     * @param addToTop if true inserts the configuration channels list to
     *                  the top of the configuration channels list of a server
     * @return 1 on success 0 on failure
     *
     * @xmlrpc.doc  Given a list of activation keys and configuration channels,
     * this method adds given configuration channels to either the top or
     * the bottom (whichever you specify) of an activation key's
     * configuration channels list. The ordering of the configuration channels
     * provided in the add list is maintained while adding.
     * If one of the configuration channels in the 'add' list
     * already exists in an activation key, the
     * configuration  channel will be re-ranked to the appropriate place.
     * @xmlrpc.param #session_key()
     * @xmlrpc.param #array_single("string", "activationKey")
     * @xmlrpc.param #array_single("string",
     *              "List of configuration channel labels in the ranked order.")
     * @xmlrpc.param #param("boolean","addToTop")
     *      #options()
     *          #item_desc ("true", "To prepend the given channels to the beginning of
     *                                 the activation key's config channel list")
     *          #item_desc ("false", "To append the given channels to the end of
     *                                     the activation key's config channel list")
     *      #options_end()
     *
     * @xmlrpc.returntype #return_int_success()
     */
    public int addConfigChannels(User loggedInUser, List<String> keys, List<String> configChannelLabels,
            boolean addToTop) {
        XmlRpcActivationKeysHelper helper = XmlRpcActivationKeysHelper.getInstance();
        List<ActivationKey> activationKeys = helper.lookupKeys(loggedInUser, keys);
        XmlRpcConfigChannelHelper configHelper = XmlRpcConfigChannelHelper.getInstance();
        List<ConfigChannel> channels = configHelper.lookupGlobals(loggedInUser, configChannelLabels);
        ConfigChannelListProcessor proc = new ConfigChannelListProcessor();
        if (addToTop) {
            Collections.reverse(channels);
        }

        for (ActivationKey key : activationKeys) {
            for (ConfigChannel chan : channels) {
                if (addToTop) {
                    proc.add(key.getConfigChannelsFor(loggedInUser), chan, 0);
                } else {
                    proc.add(key.getConfigChannelsFor(loggedInUser), chan);
                }
            }
        }
        return 1;
    }

    /**
     * removes selected channels from list of config channels provided
     * for a given list of activation keys.
     * @param loggedInUser The current user
     * @param keys the list of activation key values.
     * @param configChannelLabels sets channels labels
     * @return 1 on success 0 on failure
     *
     * @xmlrpc.doc Remove configuration channels from the given activation keys.
     * @xmlrpc.param #param("string", "sessionKey ")
     * @xmlrpc.param #array_single("string", "activationKey")
     * @xmlrpc.param #array_single("string", "configChannelLabel")
     * @xmlrpc.returntype #return_int_success()
     */
    public int removeConfigChannels(User loggedInUser, List<String> keys, List<String> configChannelLabels) {
        XmlRpcActivationKeysHelper helper = XmlRpcActivationKeysHelper.getInstance();
        List<ActivationKey> activationKeys = helper.lookupKeys(loggedInUser, keys);
        XmlRpcConfigChannelHelper configHelper = XmlRpcConfigChannelHelper.getInstance();
        List<ConfigChannel> channels = configHelper.lookupGlobals(loggedInUser, configChannelLabels);
        ConfigChannelListProcessor proc = new ConfigChannelListProcessor();
        boolean success = true;
        for (ActivationKey activationKey : activationKeys) {
            success = success && proc.remove(activationKey.getConfigChannelsFor(loggedInUser), channels);
        }
        if (success) {
            return 1;
        }
        return 0;
    }

    /**
     * Enable configuration file deployment for the specified activation key
     * @param loggedInUser The current user
     * @param key the activation key
     * @return 1 on success, 0 on failure
     *
     * @xmlrpc.doc Enable configuration file deployment for the specified activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.returntype #return_int_success()
     */
    public int enableConfigDeployment(User loggedInUser, String key) {
        ActivationKey ac = lookupKey(key, loggedInUser);
        ac.setDeployConfigs(true);
        return 1;
    }

    /**
     * Disable configuration file deployment for the specified activation key
     * @param loggedInUser The current user
     * @param key the activation key
     * @return 1 on success, 0 on failure
     *
     * @xmlrpc.doc Disable configuration file deployment for the specified activation key.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.returntype #return_int_success()
     */
    public int disableConfigDeployment(User loggedInUser, String key) {
        ActivationKey ac = lookupKey(key, loggedInUser);
        ac.setDeployConfigs(false);
        return 1;
    }

    /**
     * Check configuration file deployment status for the activation key specified.
     * @param loggedInUser The current user
     * @param key the activation key
     * @return 1 if enabled, 0 if disabled, exception thrown otherwise
     *
     * @xmlrpc.doc Check configuration file deployment status for the
     * activation key specified.
     * @xmlrpc.param #param("string", "sessionKey")
     * @xmlrpc.param #param("string", "key")
     * @xmlrpc.returntype 1 if enabled, 0 if disabled, exception thrown otherwise.
     */
    public int checkConfigDeployment(User loggedInUser, String key) {
        ActivationKey ac = lookupKey(key, loggedInUser);
        return (ac.getDeployConfigs() ? 1 : 0);
    }
}