Java tutorial
/** * 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. */ /* * Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. */ package com.redhat.rhn.manager.errata; import com.redhat.rhn.common.conf.Config; import com.redhat.rhn.common.conf.ConfigDefaults; import com.redhat.rhn.common.db.datasource.DataResult; import com.redhat.rhn.common.db.datasource.ModeFactory; import com.redhat.rhn.common.db.datasource.SelectMode; import com.redhat.rhn.common.db.datasource.WriteMode; import com.redhat.rhn.common.hibernate.HibernateFactory; import com.redhat.rhn.common.hibernate.LookupException; import com.redhat.rhn.common.localization.LocalizationService; import com.redhat.rhn.common.messaging.MessageQueue; import com.redhat.rhn.common.security.PermissionException; import com.redhat.rhn.domain.action.Action; import com.redhat.rhn.domain.action.ActionChain; import com.redhat.rhn.domain.action.ActionChainFactory; import com.redhat.rhn.domain.action.errata.ErrataAction; import com.redhat.rhn.domain.channel.Channel; import com.redhat.rhn.domain.channel.ChannelFactory; import com.redhat.rhn.domain.errata.Bug; import com.redhat.rhn.domain.errata.Errata; import com.redhat.rhn.domain.errata.ErrataFactory; import com.redhat.rhn.domain.errata.ErrataFile; import com.redhat.rhn.domain.org.Org; import com.redhat.rhn.domain.rhnset.RhnSet; import com.redhat.rhn.domain.role.RoleFactory; import com.redhat.rhn.domain.server.ManagedServerGroup; import com.redhat.rhn.domain.user.User; import com.redhat.rhn.frontend.action.channel.manage.PublishErrataHelper; import com.redhat.rhn.frontend.dto.CVE; import com.redhat.rhn.frontend.dto.ChannelOverview; import com.redhat.rhn.frontend.dto.ErrataOverview; import com.redhat.rhn.frontend.dto.OwnedErrata; import com.redhat.rhn.frontend.dto.PackageDto; import com.redhat.rhn.frontend.dto.PackageOverview; import com.redhat.rhn.frontend.dto.SystemOverview; import com.redhat.rhn.frontend.events.CloneErrataEvent; import com.redhat.rhn.frontend.events.NewCloneErrataEvent; import com.redhat.rhn.frontend.listview.PageControl; import com.redhat.rhn.frontend.xmlrpc.InvalidErrataException; import com.redhat.rhn.frontend.xmlrpc.InvalidParameterException; import com.redhat.rhn.manager.BaseManager; import com.redhat.rhn.manager.action.ActionManager; import com.redhat.rhn.manager.channel.ChannelManager; import com.redhat.rhn.manager.errata.cache.ErrataCacheManager; import com.redhat.rhn.manager.rhnset.RhnSetDecl; import com.redhat.rhn.manager.rhnset.RhnSetManager; import com.redhat.rhn.manager.system.SystemManager; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; 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; import redstone.xmlrpc.XmlRpcClient; import redstone.xmlrpc.XmlRpcFault; /** * ErrataManager is the singleton class used to provide business operations * on Errata, where those operations interact with other top tier business * objects. Operations that require changes to the Errata. * @version $Rev$ */ public class ErrataManager extends BaseManager { private static Logger log = Logger.getLogger(ErrataManager.class); public static final String DATE_FORMAT_PARSE_STRING = "yyyy-MM-dd"; public static final long MAX_ADVISORY_RELEASE = 9999; private ErrataManager() { } /** * Converts a list of ErrataFile instances into java.io.File instances * If a corresponding java.io.File instance is not found for a given * ErrataFile instance then it is skipped and not added to the returned list. * @param errataFiles list of files to resolve * @return list of corresponding java.io.File instances */ public static List resolveOvalFiles(List errataFiles) { if (errataFiles == null || errataFiles.size() == 0) { return null; } List retval = new LinkedList(); for (Iterator iter = errataFiles.iterator(); iter.hasNext();) { String directory = Config.get().getString("web.mount_point"); ErrataFile ef = (ErrataFile) iter.next(); if (directory == null) { return null; } if (!directory.endsWith("/")) { directory += "/"; } directory += "rhn/errata/oval/"; String fileName = ef.getFileName(); if (!fileName.toLowerCase().startsWith(directory)) { fileName = directory + fileName; } File f = new File(fileName); if (f.exists()) { retval.add(f); } } return retval; } /** * Tries to locate errata based on either the errataum's id or the * CVE/CAN identifier string. * @param identifier erratum id or CVE/CAN id string * @return list of erratas found */ public static List lookupErrataByIdentifier(String identifier) { return ErrataFactory.lookupByIdentifier(identifier); } /** * Takes an unpublished errata and returns a published errata into the * channels we pass in. NOTE: This method does NOT update the errata cache for * the channels. That is done when packages are pushed as part of the errata * publication process (which is not done here) * * @param unpublished The errata to publish * @param channelIds The Long channelIds we want to publish this Errata to. * @param user who is publishing errata * @return Returns a published errata. */ public static Errata publish(Errata unpublished, Collection channelIds, User user) { //pass on to the factory Errata retval = ErrataFactory.publish(unpublished); log.debug("publish - errata published"); retval = addChannelsToErrata(retval, channelIds, user); log.debug("publish - updateErrataCacheForChannelsAsync called"); // update the search server updateSearchIndex(); return retval; } /** * Takes an unpublished errata and returns a published errata * * @param unpublished The errata to publish * @return Returns a published errata. */ public static Errata publish(Errata unpublished) { //pass on to the factory Errata retval = ErrataFactory.publish(unpublished); log.debug("publish - errata published"); // update the search server updateSearchIndex(); return retval; } /** * Add the channels in the channelIds set to the passed in errata. * * @param errata to add channels to * @param channelIds to add * @param user who is adding channels to errata * @return Errata that is reloaded from the DB. */ public static Errata addChannelsToErrata(Errata errata, Collection<Long> channelIds, User user) { log.debug("addChannelsToErrata"); Iterator itr = channelIds.iterator(); while (itr.hasNext()) { Long channelId = (Long) itr.next(); Channel channel = ChannelManager.lookupByIdAndUser(channelId, user); if (channel != null) { errata.addChannel(channel); errata.addChannelNotification(channel, new Date()); } } //if we're publishing the errata but not pushing packages // We need to add cache entries for ones that are already in the channel // and associated to the errata List<Long> list = new ArrayList<Long>(); list.addAll(channelIds); ErrataCacheManager.insertCacheForChannelErrata(list, errata); //Save the errata log.debug("addChannelsToErrata - storing errata"); storeErrata(errata); errata = (Errata) HibernateFactory.reload(errata); log.debug("addChannelsToErrata - errata reloaded from DB"); return errata; } /** * Creates a new (Unpublished) Errata object. * @return Returns a fresh errata */ public static Errata createNewErrata() { return ErrataFactory.createUnpublishedErrata(); } /** * Creates a new Unpublished Bug with the id and summary given. * @param id The id for the new bug. * @param summary The summary for the new bug. * @param url The url for the new bug. * @return Returns a Bug object. */ public static Bug createNewUnpublishedBug(Long id, String summary, String url) { return ErrataFactory.createUnpublishedBug(id, summary, url); } /** * Creates a new PublishedBug with the id and summary given. * @param id The id for the new bug * @param summary The summary for the new bug * @param url The url for the new bug. * @return Returns a Bug object */ public static Bug createNewPublishedBug(Long id, String summary, String url) { return ErrataFactory.createPublishedBug(id, summary, url); } /** * Returns all of the errata. * @param user Currently logged in user. * @return all of the errata. */ public static DataResult allErrata(User user) { SelectMode m = ModeFactory.getMode("Errata_queries", "all_errata"); Map<String, Object> params = new HashMap<String, Object>(); params.put("org_id", user.getOrg().getId()); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); DataResult result = makeDataResult(params, elabParams, null, m); return result; } /** * Returns all of the errata of specified advisory type. * @param user Currently logged in user. * @param type advisory type * @return all errata of specified advisory type */ public static DataResult allErrataByType(User user, String type) { SelectMode m = ModeFactory.getMode("Errata_queries", "all_errata_by_type"); Map<String, Object> params = new HashMap<String, Object>(); params.put("org_id", user.getOrg().getId()); params.put("type", type); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); DataResult result = makeDataResult(params, elabParams, null, m); return result; } /** * Returns all of the security errata * @param user Currently logged in user. * @return all security errata */ public static DataResult allSecurityErrata(User user) { SelectMode m = ModeFactory.getMode("Errata_queries", "all_errata_by_type_with_cves"); Map<String, Object> params = new HashMap<String, Object>(); params.put("org_id", user.getOrg().getId()); params.put("type", ErrataFactory.ERRATA_TYPE_SECURITY); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); DataResult result = makeDataResult(params, elabParams, null, m); return result; } /** * Returns all of the errata in a channel * @param cid the channel id * @return all of the errata in the channel. */ public static DataResult errataInChannel(Long cid) { SelectMode m = ModeFactory.getMode("Errata_queries", "channel_errata_for_list"); Map<String, Object> params = new HashMap<String, Object>(); params.put("cid", cid); DataResult dr = m.execute(params); return dr; } /** * Returns a list of ErrataOverview whose errata contains the packages * with the given pids. * @param pids list of package ids whose errata are sought. * @return a list of ErrataOverview whose errata contains the packages * with the given pids. */ public static List<ErrataOverview> searchByPackageIds(List pids) { return ErrataFactory.searchByPackageIds(pids); } /** * Returns a list of ErrataOverview whose errata contains the packages * with the given pids. * @param pids list of package ids whose errata are sought. * @param org Organization to match results with * @return a list of ErrataOverview whose errata contains the packages * with the given pids. */ public static List<ErrataOverview> searchByPackageIdsWithOrg(List pids, Org org) { return ErrataFactory.searchByPackageIdsWithOrg(pids, org); } /** * Returns a list of ErrataOverview matching the given errata ids. * @param eids Errata ids sought. * @param org Organization to match results with * @return a list of ErrataOverview matching the given errata ids. */ public static List<ErrataOverview> search(List eids, Org org) { return ErrataFactory.search(eids, org); } /** Returns errata relevant to given server group. * @param serverGroup Server group. * @return Relevant errata for server group. */ public static DataResult relevantErrata(ManagedServerGroup serverGroup) { SelectMode m = ModeFactory.getMode("Errata_queries", "relevant_to_server_group"); Map<String, Object> params = new HashMap<String, Object>(); params.put("sgid", serverGroup.getId()); return makeDataResultNoPagination(params, null, m); } /** * Returns the relevant errata to the system set (used in SSM). * * @param user Currently logged in user. * @param types List of errata types to include * @return relevant errata. */ public static DataResult relevantErrataToSystemSet(User user, List<String> types) { SelectMode m = ModeFactory.getMode("Errata_queries", "relevant_to_system_set"); Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", user.getId()); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); DataResult dr = m.execute(params, types); dr.setElaborationParams(elabParams); return dr; } /** * Returns the relevant errata. * @param user Currently logged in user. * @return relevant errata. */ public static DataResult relevantErrata(User user) { SelectMode m = ModeFactory.getMode("Errata_queries", "relevant_errata"); Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", user.getId()); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); return makeDataResult(params, elabParams, null, m); } /** * Returns the relevant errata. * @param user Currently logged in user. * @param pc PageControl * @param typeIn String type of errata. See ErrataFactory.ERRATA_TYPE_* * @return relevant errata. */ public static DataResult relevantErrataByType(User user, PageControl pc, String typeIn) { SelectMode m = ModeFactory.getMode("Errata_queries", "relevant_errata_by_type"); Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", user.getId()); params.put("type", typeIn); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); return makeDataResult(params, elabParams, pc, m); } /** * Returns the relevant security errata. * @param user Currently logged in user. * @param pc PageControl * @return relevant errata. */ public static DataResult relevantSecurityErrata(User user, PageControl pc) { SelectMode m = ModeFactory.getMode("Errata_queries", "relevant_errata_by_type_with_cves"); Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", user.getId()); params.put("type", ErrataFactory.ERRATA_TYPE_SECURITY); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); return makeDataResult(params, elabParams, pc, m); } /** * Returns all of the unpublished errata. * @param user Currently logged in user. * @return all of the errata. */ public static DataResult unpublishedOwnedErrata(User user) { return unpublishedOwnedErrata(user, null); } /** * Returns all of the unpublished errata. * @param user Currently logged in user. * @param clazz The class you would like the return values represented as * @return all of the errata. */ public static DataResult unpublishedOwnedErrata(User user, Class clazz) { return ownedErrata(user, "unpublished_owned_errata", clazz); } /** * Returns all of the unpublished errata in the given set. * @param user Currently logged in user. * @param pc PageControl * @param label Set label * @return all of the errata. */ public static DataResult unpublishedInSet(User user, PageControl pc, String label) { return errataInSet(user, pc, "unpublished_in_set", label); } /** * Returns all of the published errata. * @param user Currently logged in user. * @return all of the errata. */ public static DataResult publishedOwnedErrata(User user) { return ownedErrata(user, "published_owned_errata"); } /** * Returns all of the published errata. * @param user Currently logged in user. * @param pc PageControl * @param label Set label * @return all of the errata. */ public static DataResult publishedInSet(User user, PageControl pc, String label) { return errataInSet(user, pc, "published_in_set", label); } /** * Returns all errata selected for cloning. * @param user Currently logged in user. * @param pc PageControl * @return errata selected for cloning */ public static DataResult selectedForCloning(User user, PageControl pc) { return errataInSet(user, pc, "in_set", "clone_errata_list"); } /** * Return a list of errata overview objects contained in a set * @param user the user doing the lookup * @param setLabel the set * @return the set of ErrataOverview */ public static DataResult<ErrataOverview> errataInSet(User user, String setLabel) { SelectMode m = ModeFactory.getMode("Errata_queries", "in_set_details"); Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", user.getId()); params.put("set_label", setLabel); DataResult dr = m.execute(params); params.remove("set_label"); dr.setElaborationParams(params); return dr; } /** * Helper method to get the unpublished/published errata * @param user Currently logged in user * @param mode Tells which mode (published/unpublished) we need to run * @return all of the errata */ private static DataResult ownedErrata(User user, String mode) { return ownedErrata(user, mode, null); } /** * Helper method to get the unpublished/published errata * @param user Currently logged in user * @param mode Tells which mode (published/unpublished) we need to run * @param clazz The class you would like the return values represented as * @return all of the errata */ private static DataResult ownedErrata(User user, String mode, Class clazz) { SelectMode m; if (clazz == null) { m = ModeFactory.getMode("Errata_queries", mode); } else { m = ModeFactory.getMode("Errata_queries", mode, clazz); } Map<String, Object> params = new HashMap<String, Object>(); params.put("org_id", user.getOrg().getId()); return makeDataResult(params, new HashMap(), null, m); } /** * Helper method to get the unpublished/published errata in the set * @param user Currently logged in user * @param pc PageControl * @param mode Tells which mode (published/unpublished) we need to run * @param label Set label * @return all of the errata */ private static DataResult errataInSet(User user, PageControl pc, String mode, String label) { SelectMode m = ModeFactory.getMode("Errata_queries", mode); Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", user.getId()); params.put("set_label", label); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); return makeDataResult(params, elabParams, pc, m); } /** * Delete published errata in the set named as label * @param user User performing the operation * @param label name of the set that contains the id's of the errata to be deleted */ public static void deletePublishedErrata(User user, String label) { DataResult dr = publishedInSet(user, null, label); deleteErrata(user, dr); } /** * Delete unpublished errata in the set named as label * @param user User performing the operation * @param label name of the set that contains the id's of the errata to be deleted */ public static void deleteUnpublishedErrata(User user, String label) { DataResult dr = unpublishedInSet(user, null, label); deleteErrata(user, dr); } /** * Delete multiple errata * @param user the user deleting * @param The list of errata ids */ private static void deleteErrata(User user, List<OwnedErrata> erratas) { RhnSet bulk = RhnSetDecl.ERRATA_TO_DELETE_BULK.get(user); bulk.clear(); for (OwnedErrata oe : erratas) { bulk.add(oe.getId()); } RhnSetManager.store(bulk); List eList = new ArrayList(); eList.addAll(bulk.getElementValues()); List<ChannelOverview> cList = listChannelForErrataFromSet(bulk); List<WriteMode> modes = new LinkedList<WriteMode>(); modes.add(ModeFactory.getWriteMode("Errata_queries", "deleteChannelErrataPackagesBulk")); modes.add(ModeFactory.getWriteMode("Errata_queries", "deleteErrataFileBulk")); modes.add(ModeFactory.getWriteMode("Errata_queries", "deleteErrataPackageBulk")); modes.add(ModeFactory.getWriteMode("Errata_queries", "deleteErrataTmpBulk")); modes.add(ModeFactory.getWriteMode("Errata_queries", "deleteServerErrataPackageCacheBulk")); modes.add(ModeFactory.getWriteMode("Errata_queries", "deleteErrataBulk")); Map errataParams = new HashMap(); Map errataOrgParams = new HashMap(); errataOrgParams.put("org_id", user.getOrg().getId()); errataParams.put("uid", user.getId()); errataOrgParams.put("uid", user.getId()); errataParams.put("set", bulk.getLabel()); errataOrgParams.put("set", bulk.getLabel()); for (WriteMode mode : modes) { if (mode.getArity() == 2) { mode.executeUpdate(errataParams); } else { mode.executeUpdate(errataOrgParams); } } bulk.clear(); RhnSetManager.store(bulk); for (ChannelOverview chan : cList) { ChannelManager.queueChannelChange(chan.getLabel(), "java::deleteErrata", "errata deletion"); } } /** * Deletes a single erratum * @param user doing the deleting * @param errata The erratum for deletion */ public static void deleteErratum(User user, Errata errata) { List<OwnedErrata> eids = new ArrayList<OwnedErrata>(); OwnedErrata oErrata = new OwnedErrata(); oErrata.setId(errata.getId()); oErrata.setAdvisory(errata.getAdvisory()); eids.add(oErrata); deleteErrata(user, eids); } /** * Get a list of channel ids, and labels that a list of errata belongs to. * @param set the set of errata ids to retrieve channels for * @return list of Channel OVerview Objects */ protected static List<ChannelOverview> listChannelForErrataFromSet(RhnSet set) { SelectMode m = ModeFactory.getMode("Errata_queries", "errata_channel_id_label"); Map map = new HashMap(); map.put("label", set.getLabel()); map.put("uid", set.getUserId()); return m.execute(map); } /** * Returns the errata with given id * @param eid errata id * @param user The user performing the lookup * @return Errata the requested errata */ public static Errata lookupErrata(Long eid, User user) { Errata returnedErrata = null; if (eid == null) { return null; } returnedErrata = ErrataFactory.lookupById(eid); SelectMode m = ModeFactory.getMode("Errata_queries", "available_to_org"); Map<String, Object> params = new HashMap<String, Object>(); params.put("org_id", user.getOrg().getId()); params.put("eid", eid); // If we didn't find an errata, throw a lookup exception if (returnedErrata == null) { LocalizationService ls = LocalizationService.getInstance(); LookupException e = new LookupException("Could not find errata: " + eid); e.setLocalizedTitle(ls.getMessage("lookup.jsp.title.errata")); e.setLocalizedReason1(ls.getMessage("lookup.jsp.reason1.errata")); e.setLocalizedReason2(ls.getMessage("lookup.jsp.reason2.errata")); throw e; } // If the errata is available to the users org, return the errata if (!m.execute(params).isEmpty()) { return returnedErrata; } // If this is a non-accessible RH errata or the errata belongs to another org, // throw a lookup exception if (returnedErrata.getOrg() == null || (returnedErrata.getOrg().getId() != user.getOrg().getId() && !user.getOrg().getTrustedOrgs().contains(returnedErrata.getOrg()))) { LocalizationService ls = LocalizationService.getInstance(); LookupException e = new LookupException("Could not find errata: " + eid); e.setLocalizedTitle(ls.getMessage("lookup.jsp.title.errata")); e.setLocalizedReason1(ls.getMessage("lookup.jsp.reason1.errata")); e.setLocalizedReason2(ls.getMessage("lookup.jsp.reason2.errata")); throw e; } // The errata belongs to the users org return returnedErrata; } /** * Returns the errata with the given advisory name * @param advisoryName The advisory name of the errata you're looking for * @return Returns the requested Errata */ public static Errata lookupByAdvisory(String advisoryName) { return ErrataFactory.lookupByAdvisory(advisoryName); } /** * Looks up errata by CVE string * @param cve errata's CVE string * @return Errata if found, otherwise null */ public static List lookupByCVE(String cve) { return ErrataFactory.lookupByCVE(cve); } /** * Lookup all Errata by Advisory Type * @param advisoryType the advisory type to use to query the set of Errata * @return List of Errata found */ public static List lookupErrataByType(String advisoryType) { return ErrataFactory.lookupErratasByAdvisoryType(advisoryType); } /** * Looks up published errata by errata id * @param id errata id * @return Errata if found, otherwise null */ public static Errata lookupPublishedErrata(Long id) { return ErrataFactory.lookupPublishedErrataById(id); } /** * Returns the systems affected by a given errata * @param user The current user * @param eid The errata id * @param pc PageControl * @return systems affected by current errata */ public static DataResult<SystemOverview> systemsAffected(User user, Long eid, PageControl pc) { SelectMode m = ModeFactory.getMode("System_queries", "affected_by_errata"); Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); params.put("user_id", user.getId()); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("eid", eid); return makeDataResult(params, elabParams, pc, m, SystemOverview.class); } /** * Returns the systems affected by a given errata * * @param user Logged-in user. * @param serverGroup Server group. * @param erratum Errata ID. * @param pc PageControl * @return systems Affected by current errata, that are in serverGroup. */ public static DataResult<SystemOverview> systemsAffected(User user, ManagedServerGroup serverGroup, Errata erratum, PageControl pc) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", erratum.getId()); params.put("user_id", user.getId()); params.put("sgid", serverGroup.getId()); return makeDataResult(params, Collections.EMPTY_MAP, pc, ModeFactory.getMode("Errata_queries", "in_group_and_affected_by_errata")); } /** * Returns the systems affected by a given errata * * @param user Logged-in user. * @param eid Errata ID. * @param pc PageControl * @return systems Affected by current errata, that are in the set of SSM. */ public static DataResult<SystemOverview> systemsAffectedInSet(User user, Long eid, PageControl pc) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); params.put("user_id", user.getId()); return makeDataResult(params, Collections.EMPTY_MAP, pc, ModeFactory.getMode("Errata_queries", "in_set_and_affected_by_errata")); } /** * Returns the system id and system names of the systems affected by a given errata * @param user The logged in user * @param eid The id of the errata in question * @return Returns the system id and system names of the systems affected by a * given errata */ public static DataResult systemsAffectedXmlRpc(User user, Long eid) { SelectMode m = ModeFactory.getMode("System_queries", "affected_by_errata_no_selectable", Map.class); Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); params.put("user_id", user.getId()); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("eid", eid); return makeDataResult(params, elabParams, null, m); } /** * Returns the systems in the current set that are affected by an errata * @param user The current user * @param label The name of the set * @param eid Errata id * @param pc PageControl * @return DataResult of systems */ public static DataResult relevantSystemsInSet(User user, String label, Long eid, PageControl pc) { SelectMode m = ModeFactory.getMode("System_queries", "in_set_and_affected_by_errata"); Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); params.put("user_id", user.getId()); params.put("set_label", label); if (pc != null) { return makeDataResult(params, params, pc, m); } DataResult dr = m.execute(params); dr.setTotalSize(dr.size()); return dr; } /** * Returns a list of available channels affected by an errata * @param user The user (to determine available channels) * @param eid The errata id * @return channels affected */ public static DataResult affectedChannels(User user, Long eid) { SelectMode m = ModeFactory.getMode("Channel_queries", "affected_by_errata"); Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); params.put("org_id", user.getOrg().getId()); DataResult dr = m.execute(params); return dr; } /** * Returns a list of bugs fixed by an errata * @param eid The errata id * @return bugs fixed */ public static DataResult bugsFixed(Long eid) { SelectMode m = ModeFactory.getMode("Errata_queries", "bugs_fixed_by_errata"); Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); DataResult dr = m.execute(params); return dr; } /** * Returns a list of CVEs for an errata * @param eid The errata id * @return common vulnerabilities and exposures */ public static DataResult errataCVEs(Long eid) { SelectMode m = ModeFactory.getMode("Errata_queries", "cves_for_errata"); Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); DataResult dr = m.execute(params); return dr; } /** * Returns a list of keywords for an errata * @param eid The errata id * @return keywords */ public static DataResult keywords(Long eid) { SelectMode m = ModeFactory.getMode("Errata_queries", "keywords"); Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", eid); DataResult dr = m.execute(params); return dr; } /** * Returns a list of advisory types available for an errata * @return advisory types */ public static List<String> advisoryTypes() { List<String> advTypes = new ArrayList<String>(); LocalizationService ls = LocalizationService.getInstance(); advTypes.add(ls.getMessage("errata.create.bugfixadvisory", LocalizationService.DEFAULT_LOCALE)); advTypes.add(ls.getMessage("errata.create.productenhancementadvisory", LocalizationService.DEFAULT_LOCALE)); advTypes.add(ls.getMessage("errata.create.securityadvisory", LocalizationService.DEFAULT_LOCALE)); return advTypes; } /** * Returns a list of l10n-ed advisory types available for an errata * @return l10n-ed advisory type labels */ public static List<String> advisoryTypeLabels() { List<String> advTypeLabels = new ArrayList<String>(); LocalizationService ls = LocalizationService.getInstance(); advTypeLabels.add(ls.getMessage("errata.create.bugfixadvisory")); advTypeLabels.add(ls.getMessage("errata.create.productenhancementadvisory")); advTypeLabels.add(ls.getMessage("errata.create.securityadvisory")); return advTypeLabels; } /** * Stores an errata to the db * @param errataIn The errata to store. */ public static void storeErrata(Errata errataIn) { ErrataFactory.save(errataIn); } /** * Sees if there is an errata with the same advisory name as the errata with eid * @param eid The id of the errata you're checking * @param name The advisory name you're checking * @return Returns true if no other errata exists with the same advisoryName, false * otherwise. */ public static boolean advisoryNameIsUnique(Long eid, String name) { Errata e = lookupByAdvisory(name); //If we can't find an errata, then the advisoryName is unique if (e == null) { return true; } //If the errata we found is the same as the one we are checking for, //then we don't care. return false. if (e.getId().equals(eid)) { return true; } return false; } /** * Get List of all cloneable errata for an org * @param orgid org we want to lookup against * @param showCloned whether we should show errata that have already been cloned * @return List of cloneableErrata */ public static DataResult clonableErrata(Long orgid, boolean showCloned) { SelectMode m; if (showCloned) { m = ModeFactory.getMode("Errata_queries", "clonable_errata_list_all"); } else { m = ModeFactory.getMode("Errata_queries", "clonable_errata_list_uncloned"); } Map<String, Object> params = new HashMap<String, Object>(); params.put("org_id", orgid); return makeDataResult(params, params, null, m); } /** * Get List of cloneable Errata for an org, from a particular channel * @param orgid org we want to lookup against * @param cid channelid * @param showCloned whether we should show errata that have already been cloned * @return List of cloneableErrata */ public static DataResult clonableErrataForChannel(Long orgid, Long cid, boolean showCloned) { SelectMode m; if (showCloned) { m = ModeFactory.getMode("Errata_queries", "clonable_errata_for_channel_all"); } else { m = ModeFactory.getMode("Errata_queries", "clonable_errata_for_channel_uncloned"); } Map<String, Object> params = new HashMap<String, Object>(); params.put("channel_id", cid); params.put("org_id", orgid); return makeDataResult(params, params, null, m); } /** * Get a list of channels applicable to the erratum * @param eid The id of the erratum * @param orgid The id for the org we want to lookup against * @param pc The page control for the user * @param clazz The class you would like the return values represented as * @return List of applicable channels for the erratum (that the org has access to) */ public static DataResult applicableChannels(Long eid, Long orgid, PageControl pc, Class clazz) { SelectMode m; if (clazz == null) { m = ModeFactory.getMode("Channel_queries", "org_errata_channels"); } else { m = ModeFactory.getMode("Channel_queries", "org_errata_channels", clazz); } Map<String, Object> params = new HashMap<String, Object>(); params.put("org_id", orgid); params.put("eid", eid); return makeDataResult(params, params, pc, m); } /** * Create a clone of the errata * @param user user performing the cloning * @param e errata to be cloned * @return clone of the errata */ public static Errata createClone(User user, Errata e) { return ErrataFactory.createClone(user.getOrg(), e); } /** * Lookup all the clones of a particular errata * looks up unpublished first, and then if none of those * exist, it looks up published ones * @param user User that is performing the cloning operation * @param original Original errata that the clones are clones of * @return list of clones of the errata */ public static List lookupByOriginal(User user, Errata original) { return ErrataFactory.lookupByOriginal(user.getOrg(), original); } /** * Lookup all the clones of a particular errata * @param user User that is performing the cloning operation * @param original Original errata that the clones are clones of * @return list of clones of the errata */ public static List lookupPublishedByOriginal(User user, Errata original) { return ErrataFactory.lookupPublishedByOriginal(user.getOrg(), original); } /** * Lists errata present in both channels * @param user user * @param channelFrom channel1 * @param channelTo channel2 * @return list of errata */ public static List listSamePublishedInChannels(User user, Channel channelFrom, Channel channelTo) { return ErrataFactory.listSamePublishedInChannels(user.getOrg(), channelFrom, channelTo); } /** * Lists errata from channelFrom, that are cloned from the same original * as errata in channelTo * @param user user * @param channelFrom channel1 * @param channelTo channel2 * @return list of errata */ public static List listPublishedBrothersInChannels(User user, Channel channelFrom, Channel channelTo) { return ErrataFactory.listPublishedBrothersInChannels(user.getOrg(), channelFrom, channelTo); } /** * Lists errata from channelFrom, that have clones in channelTo * @param user user * @param channelFrom channel1 * @param channelTo channel2 * @return list of errata */ public static List listPublishedClonesInChannels(User user, Channel channelFrom, Channel channelTo) { return ErrataFactory.listPublishedClonesInChannels(user.getOrg(), channelFrom, channelTo); } /** * Lookup packages that are associated with errata in the RhnSet "errata_list" * @param srcChan the source channel to find the package associations with * @param destChan if srcChan is not available, we will match package associations * based on packages in the destChan * @param user the user doing the query * @param set the set label * @return List of packages */ public static DataResult<PackageOverview> lookupPacksFromErrataSet(Channel srcChan, Channel destChan, User user, String set) { String mode; Map<String, Object> params = new HashMap<String, Object>(); params.put("uid", user.getId()); params.put("set", set); if (srcChan != null) { mode = "find_packages_for_errata_set_with_assoc"; params.put("src_cid", srcChan.getId()); params.put("dest_cid", destChan.getId()); } else { mode = "find_packages_for_errata_set_no_chan"; params.put("dest_cid", destChan.getId()); } SelectMode m = ModeFactory.getMode("Errata_queries", mode); return m.execute(params); } /** * Lookup errata that are in the set * @param user the user to search the set for * @param setLabel the set label * @return list of Errata Overview Objects */ public static DataResult<ErrataOverview> lookupErrataListFromSet(User user, String setLabel) { Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", user.getId()); params.put("set", setLabel); Map<String, Object> elabParams = new HashMap<String, Object>(); elabParams.put("user_id", user.getId()); SelectMode m = ModeFactory.getMode("Errata_queries", "errata_list_in_set"); return makeDataResult(params, elabParams, null, m); } /** * Finds the packages contained in an errata that apply to a channel * @param customChan the channel to look in * @param errata the errata to look for packs with * @param user the user doing the request. * @return collection of PackageOverview objects */ public static DataResult<PackageOverview> lookupPacksFromErrataForChannel(Channel customChan, Errata errata, User user) { Map<String, Object> params = new HashMap<String, Object>(); //params.put("uid", user.getId()); params.put("eid", errata.getId()); params.put("org_id", user.getOrg().getId()); params.put("custom_cid", customChan.getId()); SelectMode m = ModeFactory.getMode("Errata_queries", "find_packages_for_errata_and_channel"); return m.execute(params); } /** * Finds the packages contained in an errata that apply to a channel * @param channelId the channel to look in * @param errataId the errata to look for packs with * @return collection of PackageDto objects */ public static DataResult<PackageDto> lookupPacksFromErrataForChannel(Long channelId, Long errataId) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", errataId); params.put("cid", channelId); SelectMode m = ModeFactory.getMode("Errata_queries", "find_packages_for_errata_and_channel_simple"); return m.execute(params); } /** * Finds the bugs associated with an erratum * @param erratumId the erratum to look for * @return collection of Bug (dto) objects */ public static DataResult<com.redhat.rhn.frontend.dto.Bug> lookupBugsForErratum(Long erratumId) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", erratumId); SelectMode m = ModeFactory.getMode("Errata_queries", "find_bugs_for_erratum"); return m.execute(params); } /** * Finds the cves associated with an erratum * @param erratumId the erratum to look for * @return collection of cves (String) */ public static DataResult<CVE> lookupCvesForErratum(Long erratumId) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", erratumId); SelectMode m = ModeFactory.getMode("Errata_queries", "find_cves_for_erratum"); return m.execute(params); } /** * Finds the keywords associated with an erratum * @param erratumId the erratum to look for * @return collection of keywords (String) */ public static List<String> lookupKeywordsForErratum(Long erratumId) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", erratumId); SelectMode m = ModeFactory.getMode("Errata_queries", "find_keywords_for_erratum"); List<Map<String, String>> results = m.execute(params); List<String> ret = new ArrayList<String>(); for (Map<String, String> row : results) { ret.add(row.get("keyword")); } return ret; } /** * Lists the packages contained in an errata associated to a channel * @param customChan the channel to look in * @param errata the errata to look for packs with * @param user the user doing the request. * @return collection of PackageOverview objects */ public static DataResult<PackageOverview> listErrataChannelPacks(Channel customChan, Errata errata, User user) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", errata.getId()); params.put("org_id", user.getOrg().getId()); params.put("custom_cid", customChan.getId()); SelectMode m = ModeFactory.getMode("Errata_queries", "find_errata_channel_packages"); return m.execute(params); } /** * Finds the errata ids issued between start and end dates. * @param start String start date * @param end String end date * @return errata ids issued between start -> end */ public static List<Long> listErrataIdsIssuedBetween(String start, String end) { String mode = "issued_between"; Map<String, Object> params = new HashMap<String, Object>(); if (!StringUtils.isEmpty(start)) { params.put("start_date_str", start); } if (!StringUtils.isEmpty(end)) { params.put("end_date_str", end); } SelectMode m = ModeFactory.getMode("Errata_queries", mode); DataResult result = m.execute(params); List ids = new ArrayList<Long>(); for (Iterator iter = result.iterator(); iter.hasNext();) { Map row = (Map) iter.next(); Long rawId = (Long) row.get("id"); ids.add(rawId); } return ids; } /** * remove an erratum for a channel and updates the errata cache accordingly * @param errata the errata to remove * @param chan the channel to remove the erratum from * @param user the user doing the removing */ public static void removeErratumFromChannel(Errata errata, Channel chan, User user) { if (!user.hasRole(RoleFactory.CHANNEL_ADMIN)) { throw new PermissionException(RoleFactory.CHANNEL_ADMIN); } //Since we don't remove the packages, we need to insert those entries // in case they aren't already there. // So we are inserting (systemID, packageId) entries, because we're // going to delete the (systemId, packageId, errataId) entries List<Long> pids = ErrataFactory.listErrataChannelPackages(chan.getId(), errata.getId()); ErrataCacheManager.insertCacheForChannelPackages(chan.getId(), null, pids); //Remove the errata from the channel chan.getErratas().remove(errata); List<Long> eList = new ArrayList<Long>(); eList.add(errata.getId()); //First delete the cache entries ErrataCacheManager.deleteCacheEntriesForChannelErrata(chan.getId(), eList); // Then we need to see if the errata is in any other channels within the // channel tree. List<Channel> cList = new ArrayList<Channel>(); if (chan.isBaseChannel()) { cList.addAll(ChannelFactory.listAllChildrenForChannel(chan)); } else { //add parent Channel parent = chan.getParentChannel(); cList.add(parent); //add parent //add sibbling and self cList.addAll(ChannelFactory.listAllChildrenForChannel(parent)); cList.remove(chan); //remove self } for (Channel tmpChan : cList) { if (tmpChan.getErratas().contains(errata)) { List<Long> tmpCidList = new ArrayList<Long>(); tmpCidList.add(tmpChan.getId()); ErrataCacheManager.insertCacheForChannelErrataAsync(tmpCidList, errata); } } } /** * Publish errata to a channel asynchronously (cloning as necessary), * does not do any package push * @param chan the channel * @param errataIds list of errata ids * @param user the user doing the push */ public static void publishErrataToChannelAsync(Channel chan, Collection<Long> errataIds, User user) { Logger.getLogger(ErrataManager.class).debug("Publishing"); CloneErrataEvent eve = new CloneErrataEvent(chan, errataIds, user); MessageQueue.publish(eve); } /** * Clone errata to a channel * @param chan the channel * @param errata list of errata ids * @param user the user doing the push * @param inheritPackages inherit packages from the original bug (instaed of the * clone in the case of a clone of a clone) * @return an array of Errata that have been published */ public static Object[] cloneErrataApi(Channel chan, Collection<Errata> errata, User user, boolean inheritPackages) { return cloneErrataApi(chan, errata, user, inheritPackages, true); } /** * Clone errata to a channel * @param chan the channel * @param errata list of errata ids * @param user the user doing the push * @param inheritPackages inherit packages from the original bug (instaed of the * clone in the case of a clone of a clone) * @param performPostActions true (default) if you want to refresh newest package * cache and schedule repomd regeneration. False only if you're going to do those * things yourself. * @return an array of Errata that have been published */ public static Object[] cloneErrataApi(Channel chan, Collection<Errata> errata, User user, boolean inheritPackages, boolean performPostActions) { List<Errata> errataToPublish = new ArrayList<Errata>(); // For each errata look up existing clones, or manually clone it for (Errata toClone : errata) { if (toClone.isCloned()) { errataToPublish.add(toClone); } else { List<Errata> clones = ErrataManager.lookupPublishedByOriginal(user, toClone); if (clones.isEmpty()) { errataToPublish.add(PublishErrataHelper.cloneErrataFast(toClone, user.getOrg())); } else { errataToPublish.add(clones.get(0)); } } } List<Errata> published = ErrataFactory.publishToChannel(errataToPublish, chan, user, inheritPackages, performPostActions); for (Errata e : published) { ErrataFactory.save(e); } return published.toArray(); } /** * Clone errata as necessary and link cloned errata with new channel. * Warning: this does not clone packages or schedule channel repomd regeneration. * You must do that yourself! * @param fromCid id of old channel * @param toCid id of channel to clone into * @param user the requesting user */ public static void cloneChannelErrata(Long fromCid, Long toCid, User user) { List<ErrataOverview> toClone = ErrataFactory.relevantToOneChannelButNotAnother(fromCid, toCid); cloneChannelErrata(toClone, toCid, user); } /** * Clone errata as necessary and link cloned errata with new channel. * Warning: this does not clone packages or schedule channel repomd regeneration. * You must do that yourself! * @param toClone List of ErrataOverview to clone * @param toCid Channel id to clone them into * @param user the requesting user */ public static void cloneChannelErrata(List<ErrataOverview> toClone, Long toCid, User user) { List<OwnedErrata> owned = ErrataFactory.listPublishedOwnedUnmodifiedClonedErrata(user.getOrg().getId()); List<Long> eids = new ArrayList<Long>(); // add published, cloned, owned errata to mapping. we want the oldest owned // clone to reuse. listPublishedOwnedUnmodifiedClonedErrata orders by created, // so we just add the first one we come across to the mapping and skip others Map<Long, OwnedErrata> eidToClone = new HashMap<Long, OwnedErrata>(); for (OwnedErrata erratum : owned) { if (!eidToClone.containsKey(erratum.getFromErrataId())) { eidToClone.put(erratum.getFromErrataId(), erratum); } // add self id mapping too in case we are cloning the clone if (!eidToClone.containsKey(erratum.getId())) { eidToClone.put(erratum.getId(), erratum); } } for (ErrataOverview erratum : toClone) { if (!eidToClone.containsKey(erratum.getId())) { // no published owned clones yet, lets make our own // hibernate was too slow, had to rewrite in mode queries Long cloneId = PublishErrataHelper.cloneErrataFaster(erratum.getId(), user.getOrg()); eids.add(cloneId); } else { // we have one already, reuse it eids.add(eidToClone.get(erratum.getId()).getId()); } } ChannelFactory.addClonedErrataToChannel(eids, toCid); } /** * Clone errata to a channel asynchronously * @param chan the channel * @param errata list of errata ids * @param user the user doing the push * @param inheritPackages inherit packages from the original bug (instead of the * clone in the case of a clone of a clone) */ public static void cloneErrataApiAsync(Channel chan, List<Long> errata, User user, boolean inheritPackages) { Logger.getLogger(ErrataManager.class).debug("Cloning"); ChannelFactory.lock(chan); for (long eid : errata) { NewCloneErrataEvent neve = new NewCloneErrataEvent(chan, eid, user, inheritPackages); neve.register(); MessageQueue.publish(neve); } } /** * Check if the channel has pending asynchronous errata clone jobs * @param channel channel to check * @return true if there are pending jobs, false otherwise */ public static boolean channelHasPendingAsyncCloneJobs(Channel channel) { return AsyncErrataCloneCounter.getInstance().channelHasPendingJobs(channel.getId()); } /** * Send errata notifications for a particular errata and channel * @param e the errata to send notifications about * @param chan the channel with which to decide which systems * and users to send errata for * @param date the date */ public static void addErrataNotification(Errata e, Channel chan, Date date) { Map<String, Object> params = new HashMap<String, Object>(); params.put("cid", chan.getId()); params.put("eid", e.getId()); java.sql.Date newDate = new java.sql.Date(date.getTime()); params.put("datetime", newDate); WriteMode m = ModeFactory.getWriteMode("Errata_queries", "insert_errata_notification"); m.executeUpdate(params); } /** * Delete all errata notifications for an errata * @param e the errata to clear notifications for */ public static void clearErrataNotifications(Errata e) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", e.getId()); WriteMode m = ModeFactory.getWriteMode("Errata_queries", "clear_errata_notification"); m.executeUpdate(params); } /** * Delete all errata notifications for an errata in specified channel * @param e the errata to clear notifications for * @param c affected channel */ public static void clearErrataChannelNotifications(Errata e, Channel c) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", e.getId()); params.put("cid", c.getId()); WriteMode m = ModeFactory.getWriteMode("Errata_queries", "clear_errata_channel_notification"); m.executeUpdate(params); } /** * List queued errata notifications * @param e the errata * @return list of maps */ public static List listErrataNotifications(Errata e) { Map<String, Object> params = new HashMap<String, Object>(); params.put("eid", e.getId()); SelectMode m = ModeFactory.getMode("Errata_queries", "list_errata_notification"); return m.execute(params); } /** * update the errata search index. * @return true if index was updated, false otherwise. */ private static boolean updateSearchIndex() { boolean flag = false; try { XmlRpcClient client = new XmlRpcClient(ConfigDefaults.get().getSearchServerUrl(), true); List args = new ArrayList(); args.add("errata"); Boolean rc = (Boolean) client.invoke("admin.updateIndex", args); flag = rc.booleanValue(); } catch (XmlRpcFault e) { // right now updateIndex doesn't throw any faults. log.error("Errata index not updated. Search server unavailable." + "ErrorCode = " + e.getErrorCode(), e); e.printStackTrace(); } catch (Exception e) { // if the search server is down, folks will know when they // attempt to search. If this call failed the errata in // question won't be searchable immediately, but will get picked // up the next time the search server runs the job (after being // restarted. log.error("Errata index not updated. Search server unavailable.", e); } return flag; } /** * Apply errata updates to a system list at a specified time. * @param loggedInUser The logged in user * @param systemIds list of system IDs * @param errataIds List of errata IDs to apply (as Integers) * @param earliestOccurrence Earliest occurrence of the errata update * @return list of action ids */ public static List<Long> applyErrataHelper(User loggedInUser, List<Long> systemIds, List<Integer> errataIds, Date earliestOccurrence) { if (systemIds.isEmpty()) { throw new InvalidParameterException("No systems specified."); } if (errataIds.isEmpty()) { throw new InvalidParameterException("No errata to apply."); } // at this point all errata is applicable to all systems, so let's apply return applyErrata(loggedInUser, errataIds, earliestOccurrence, null, systemIds, false); } /** * Apply a list of errata to a list of servers. * @param user user * @param errataIds errata ids * @param earliest schedule time * @param serverIds server ids * @return list of action ids */ public static List<Long> applyErrata(User user, List errataIds, Date earliest, List<Long> serverIds) { return applyErrata(user, errataIds, earliest, null, serverIds); } /** * Apply a list of errata to a list of servers, with an optional Action * Chain. * Note that not all erratas are applied to all systems. Systems get * only the erratas relevant for them. * @param user user * @param errataIds errata ids * @param earliest schedule time * @param actionChain the action chain to add the action to or null * @param serverIds server ids * @return list of action ids */ public static List<Long> applyErrata(User user, List errataIds, Date earliest, ActionChain actionChain, List<Long> serverIds) { return applyErrata(user, errataIds, earliest, actionChain, serverIds, true); } /** * Apply a list of errata to a list of servers, with an optional Action * Chain. * Note that not all erratas are applied to all systems. Systems get * only the erratas relevant for them. * * @param user user * @param errataIds errata ids * @param earliest schedule time * @param actionChain the action chain to add the action to or null * @param serverIds server ids * @param onlyRelevant If true not all erratas are applied to all systems. * Systems get only the erratas relevant for them. * If false, InvalidErrataException is thrown if an errata does not apply * to a system. * @return list of action ids */ private static List<Long> applyErrata(User user, List errataIds, Date earliest, ActionChain actionChain, List<Long> serverIds, boolean onlyRelevant) { // not all errata applies to all systems, so we will group actions per systems // having the same sets of errata // We can't do a Set<Errata> because AbstractErrata equals/hashCode does not use Id. // System Id -> Errata Ids Map<Long, Set<Long>> relevantErrataForServer = new HashMap<Long, Set<Long>>(); for (Long serverId : serverIds) { List<Errata> relevantErrata = SystemManager.unscheduledErrata(user, serverId, null); Set<Long> relevantErrataIds = new HashSet<Long>(); for (Errata e : relevantErrata) { relevantErrataIds.add(e.getId()); } Set<Long> effectiveErrataIds = new HashSet<Long>(); for (Object errataIdObject : errataIds) { // HACK: ugly conversion needed because in some cases errataIds contains // Integers, in other cases Longs Long errataId = ((Number) errataIdObject).longValue(); if (relevantErrataIds.contains(errataId)) { effectiveErrataIds.add(errataId); } else { if (!onlyRelevant) { throw new InvalidErrataException(); } } } relevantErrataForServer.put(serverId, effectiveErrataIds); } Map<Set<Long>, List<Long>> serversForErrataSet = new HashMap<Set<Long>, List<Long>>(); for (Long serverId : relevantErrataForServer.keySet()) { Set<Long> errataSet = relevantErrataForServer.get(serverId); List<Long> serverList = serversForErrataSet.get(errataSet); if (serverList == null) { serverList = new ArrayList<Long>(); serversForErrataSet.put(errataSet, serverList); } serverList.add(serverId); } List<Long> actionIds = new ArrayList<Long>(); for (Set<Long> relevantErrataIds : serversForErrataSet.keySet()) { List<Long> affectedServers = serversForErrataSet.get(relevantErrataIds); // Schedule updates to the software update stack first List<ErrataAction> stackUpdates = null; List<Errata> errata = new ArrayList<Errata>(); for (Long eid : relevantErrataIds) { Errata erratum = ErrataManager.lookupErrata(eid, user); if (erratum.hasKeyword("restart_suggested")) { if (stackUpdates == null) { stackUpdates = createErrataActions(user, erratum, earliest, actionChain, affectedServers); } else { for (ErrataAction stackUpdate : stackUpdates) { stackUpdate.addErrata(erratum); } } } else { errata.add(erratum); } } if (stackUpdates != null) { for (ErrataAction stackUpdate : stackUpdates) { Object[] args = new Object[] { stackUpdate.getErrata().size() }; stackUpdate.setName(LocalizationService.getInstance().getMessage("errata.swstack", args)); ActionManager.storeAction(stackUpdate); } } // Schedule remaining errata actions for (Errata e : errata) { List<ErrataAction> errataActions = createErrataActions(user, e, earliest, actionChain, affectedServers); for (ErrataAction errataAction : errataActions) { Action action = ActionManager.storeAction(errataAction); actionIds.add(action.getId()); } } } return actionIds; } /** * Creates errata actions for the specified servers. * @param user the user * @param erratum the erratum * @param earliest the earliest * @param actionChain the action chain to add the actions to or null * @param serverIds the server ids * @return the list */ private static List<ErrataAction> createErrataActions(User user, Errata erratum, Date earliest, ActionChain actionChain, List<Long> serverIds) { List<ErrataAction> result = new LinkedList<ErrataAction>(); if (actionChain == null) { ErrataAction errataAction = (ErrataAction) ActionManager.createErrataAction(user, erratum); if (earliest != null) { errataAction.setEarliestAction(earliest); } for (Long serverId : serverIds) { ActionManager.addServerToAction(serverId, errataAction); } result.add(errataAction); } else { int sortOrder = ActionChainFactory.getNextSortOrderValue(actionChain); for (Long serverId : serverIds) { ErrataAction errataAction = (ErrataAction) ActionManager.createErrataAction(user, erratum); if (earliest != null) { errataAction.setEarliestAction(earliest); } ActionChainFactory.queueActionChainEntry(errataAction, actionChain, serverId, sortOrder); result.add(errataAction); } } return result; } }