/** * 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.domain.rhnset; import com.redhat.rhn.common.db.ConstraintViolationException; import com.redhat.rhn.common.db.WrappedSQLException; 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 org.apache.log4j.Logger; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * RhnSetFactory * @version $Rev$ */ public class RhnSetFactory extends HibernateFactory { private static final String CATALOG = "Set_queries"; private static RhnSetFactory singleton = new RhnSetFactory(); private static Logger log = Logger.getLogger(RhnSetFactory.class); /** * Constructs the RhnSetFactory, marked private * since all methods are static. */ private RhnSetFactory() { } /** * {@inheritDoc} */ protected Logger getLogger() { return log; } /** * Finds the RhnSet which matches the given uid and label. * Returns null if no matches found. * @param uid Userid of RhnSet * @param label Label of RhnSet * @param cleanup TODO * @return the RhnSet which matched the given uid and label. */ public static RhnSet lookupByLabel(Long uid, String label, SetCleanup cleanup) { Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", uid); params.put("label", label); SelectMode m = ModeFactory.getMode(CATALOG, "lookup_set"); DataResult elements = m.execute(params); RhnSetImpl result = singleton.createFromList(elements, cleanup); if (result != null) { result.sync(); } return result; } /** * Creates an RhnSet from a List of RhnSetElements. * Returns null if elements are null or contain no items. * @param elements list of RhnSetElements * @param cleanup the cleanup that should be run when the set is stored * @return a newly created RhnSet with the given userid and label, and * all elements populated. */ private RhnSetImpl createFromList(List elements, SetCleanup cleanup) { if (elements == null || elements.isEmpty()) { return null; } RhnSetElement element = (RhnSetElement)elements.get(0); RhnSetImpl set = new RhnSetImpl(element.getUserId(), element.getLabel(), cleanup); Iterator itr = elements.iterator(); while (itr.hasNext()) { element = (RhnSetElement) itr.next(); set.addElement(element); } return set; } /** * Returns a new RhnSet. * @param userid userid associated with this set. * @param label set label. * @param cleanup the cleanup that should be run when the set is stored * @return a newly created RhnSet with the given userid and label, * with an empty elements list. */ public static RhnSet createRhnSet(Long userid, String label, SetCleanup cleanup) { return new RhnSetImpl(userid, label, cleanup); } /** * Persists the given RhnSet to the database. * @param set RhnSet to be persisted. */ public static void save(RhnSet set) { RhnSetImpl simpl = (RhnSetImpl) set; // The updates really need to be batched if (simpl.isSynced() && !simpl.getElements().isEmpty()) { WriteMode deleteEl3 = writeMode("delete_from_set_el3"); WriteMode deleteEl2 = writeMode("delete_from_set_el2"); WriteMode deleteEl1 = writeMode("delete_from_set_el1"); for (Iterator i = simpl.getRemoved().iterator(); i.hasNext();) { RhnSetElement current = (RhnSetElement) i.next(); executeMode(current, deleteEl3, deleteEl2, deleteEl1); } } else { removeByLabel(simpl.getUserId(), simpl.getLabel()); } Set added; if (!simpl.isSynced()) { added = simpl.getElements(); } else { added = simpl.getAdded(); } WriteMode insertEl3 = writeMode("add_to_set_el3"); WriteMode insertEl2 = writeMode("add_to_set_el2"); WriteMode insertEl1 = writeMode("add_to_set_el1"); for (Iterator i = added.iterator(); i.hasNext();) { RhnSetElement current = (RhnSetElement) i.next(); try { executeMode(current, insertEl3, insertEl2, insertEl1); } catch (ConstraintViolationException e) { // a concurrent transaction has already inserted this row // and COMMITted. This is tolerable and can happen because // the default transaction isolation level is READ // COMMITTED, thus this exception can be safely ignored } catch (WrappedSQLException e) { if (e.getMessage().contains("violates unique constraint")) { // see ConstraintViolationException } } } if (!added.isEmpty()) { simpl.getCleanup().cleanup(simpl); } simpl.sync(); } /** * Cleanup the set. That is useful, when some of the items included in the set were * removed from database. That might have invalidated part of the set. * @param set RhnSet to cleanup. */ public static void cleanup(RhnSet set) { RhnSetImpl simpl = (RhnSetImpl) set; simpl.getCleanup().cleanup(simpl); // Even palindrom can save the day. } private static WriteMode writeMode(String modeName) { return ModeFactory.getWriteMode(CATALOG, modeName); } private static void executeMode(RhnSetElement elem, WriteMode el3, WriteMode el2, WriteMode el1) { Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", elem.getUserId()); params.put("label", elem.getLabel()); params.put("el_one", elem.getElement()); int count; if (elem.getElementThree() == null && elem.getElementTwo() == null) { count = el1.executeUpdate(params); } else if (elem.getElementThree() == null) { params.put("el_two", elem.getElementTwo()); count = el2.executeUpdate(params); } else { params.put("el_three", elem.getElementThree()); params.put("el_two", elem.getElementTwo()); count = el3.executeUpdate(params); } assert count == 1 : "Failed to update row"; } /** * Removes a set by label and userid. * @param userId The userid associated with the set. * @param label The set's label. */ public static void removeByLabel(Long userId, String label) { WriteMode m = ModeFactory.getWriteMode(CATALOG, "delete_set"); Map<String, Object> params = new HashMap<String, Object>(); params.put("user_id", userId); params.put("label", label); m.executeUpdate(params); } /** * Remove a set * @param set the set to remove */ public static void remove(RhnSet set) { removeByLabel(set.getUserId(), set.getLabel()); RhnSetImpl simpl = (RhnSetImpl) set; simpl.getElements().clear(); simpl.sync(); } }