package br.uff.ic.dyevc.persistence; //~--- non-JDK imports -------------------------------------------------------- import br.uff.ic.dyevc.exception.RepositoryReferencedException; import br.uff.ic.dyevc.exception.ServiceException; import br.uff.ic.dyevc.model.topology.RepositoryFilter; import br.uff.ic.dyevc.model.topology.RepositoryInfo; import br.uff.ic.dyevc.model.topology.Topology; import br.uff.ic.dyevc.services.MongoLabProvider; import br.uff.ic.dyevc.utils.DateUtil; import br.uff.ic.dyevc.utils.SystemUtils; import org.slf4j.LoggerFactory; //~--- JDK imports ------------------------------------------------------------ import java.util.ArrayList; import java.util.Date; import java.util.Set; /** * Data Access Object to manipulate topology information * * @author Cristiano */ public class TopologyDAO { /** * Retrieves the topology for a specific system * * @param systemName the name of the system to retrieve the topology * @return the known topology for the specified system * @throws ServiceException */ public Topology readTopologyForSystem(String systemName) throws ServiceException { LoggerFactory.getLogger(TopologyDAO.class).trace("readTopologyForSystem -> Entry"); Topology result = new Topology(); MongoLabServiceParms parms = new MongoLabServiceParms(); RepositoryFilter filter = new RepositoryFilter(); filter.setSystemName(systemName); parms.setQuery(filter); ArrayList<RepositoryInfo> repositories = MongoLabProvider.getRepositories(parms); result.resetTopology(repositories); LoggerFactory.getLogger(TopologyDAO.class).trace("readTopologyForSystem -> Exit"); return result; } /** * Retrieves the entire topology for all known systems from the database * * @return the entire known topology for all systems * @throws ServiceException */ public Topology readTopology() throws ServiceException { LoggerFactory.getLogger(TopologyDAO.class).trace("readTopology -> Entry"); Topology result = new Topology(); ArrayList<RepositoryInfo> repositories = MongoLabProvider.getRepositories(null); result.resetTopology(repositories); LoggerFactory.getLogger(TopologyDAO.class).trace("readTopology -> Exit"); return result; } /** * Retrieves a list of repositories that match the filter criteria * * @param repFilter Filter to be applied * @return List of repositories that match the specified filter * @throws ServiceException */ public ArrayList<RepositoryInfo> getRepositoriesByQuery(RepositoryFilter repFilter) throws ServiceException { LoggerFactory.getLogger(TopologyDAO.class).trace("getRepositoriesByQuery -> Entry"); MongoLabServiceParms parms = new MongoLabServiceParms(); parms.setQuery(repFilter); ArrayList<RepositoryInfo> result = MongoLabProvider.getRepositories(parms); LoggerFactory.getLogger(TopologyDAO.class).trace("getRepositoriesByQuery -> Exit"); return result; } /** * Retrieves the list of repositories that depends on the repository with the specified id, either by a pushesTo or * by a pullsFrom dependency * * @param id Id of the repository to look for * @return List of repositories that relates to the specified repository * @throws ServiceException */ public ArrayList<RepositoryInfo> findDependentRepositories(String id) throws ServiceException { LoggerFactory.getLogger(TopologyDAO.class).trace("findDependentRepositories -> Entry"); String query = "{\"$or\": [{\"pushesTo\": \"" + id + "\"}, " + "{\"pullsFrom\": \"" + id + "\"}]}"; MongoLabServiceParms parms = new MongoLabServiceParms(); parms.setQuery(query); ArrayList<RepositoryInfo> result = MongoLabProvider.getRepositories(parms); LoggerFactory.getLogger(TopologyDAO.class).trace("findDependentRepositories -> Exit"); return result; } /** * Update all the repositories in the specified list. If an element does not yet exists, then create it * * @param repositories List of repositories to be upserted * @return The last changed date/time for this group of repositories * @exception ServiceException */ public Date upsertRepositories(ArrayList<RepositoryInfo> repositories) throws ServiceException { LoggerFactory.getLogger(TopologyDAO.class).trace("upsertRepositories -> Entry"); Date lastChanged = DateUtil.getLocalTimeInUTC(); for (RepositoryInfo repository : repositories) { repository.setLastChanged(lastChanged); upsertRepository(repository); } LoggerFactory.getLogger(TopologyDAO.class).trace("upsertRepositories -> Exit"); return lastChanged; } /** * Update a repository in the database. If the repository does not exist, inserts it * * @param repository The repository to be updated in the database. * @throws ServiceException * @return The last changed date/time for this repository */ public Date upsertRepository(RepositoryInfo repository) throws ServiceException { Date lastChanged = repository.getLastChanged(); if (lastChanged == null) { lastChanged = DateUtil.getLocalTimeInUTC(); repository.setLastChanged(lastChanged); } MongoLabProvider.upsertRepository(repository); return lastChanged; } /** * <p> * Deletes the monitored repository with the specified id in the specified system from the database.</p> * <p> * The application first checks if the repository is not referenced anywhere, throwing an exception in that case. * </p> * <p> * If the monitored repository does not have a system name configured, ignores it and does nothing, returning * null.</p> * <p> * If the repository is monitored by someone else, just removes this hostname from the list, keeping it in the * database</p> * * @param systemName System where the repository belongs to * @param repId the Id of the repository to be deleted * @param removeFromMonitoring If true, remove this hostname from the list of hostnames that monitor the repository. * @throws br.uff.ic.dyevc.exception.ServiceException when an error occurred calling the provider * @throws RepositoryReferencedException when other repositories reference this one * @return The date/time this repository was deleted or null if it was not deleted. */ public Date deleteRepository(String systemName, String repId, boolean removeFromMonitoring) throws ServiceException, RepositoryReferencedException { Date lastChanged = null; // Only repositories with system names have to be deleted from the database if (("".equals(systemName) || "no name".equals(systemName))) { return null; } RepositoryFilter filter = new RepositoryFilter(); filter.setSystemName(systemName); filter.setId(repId); ArrayList<RepositoryInfo> reps = getRepositoriesByQuery(filter); // Only one repository should be returned from above query. If no record is returned, than this repository // was already deleted. if (reps.isEmpty()) { return null; } // Removes this hostname from the list of hostnames that monitor this repository RepositoryInfo info = reps.get(0); Set<String> monitoredBy = info.getMonitoredBy(); boolean changed = false; ArrayList<RepositoryInfo> dependentRepositories = null; if (removeFromMonitoring) { changed = monitoredBy.remove(SystemUtils.getLocalHostname()); } if (monitoredBy.isEmpty()) { // if no one else monitors this repository, then it can be removed from topology // Verify if there is any repository that pushes to or pulls from this repository. dependentRepositories = findDependentRepositories(repId); if (dependentRepositories.isEmpty()) { // No one depends upon this repository. Verifies if any repository depends upon this repository's push or pull // list. If not, than these repositories can be deleted as well lastChanged = doRemove(info); } else if (changed) { // if someone else monitors this repository and its monitoredBy list was changed, updates it lastChanged = upsertRepository(info); } } if ((dependentRepositories != null) &&!dependentRepositories.isEmpty()) { throw new RepositoryReferencedException(dependentRepositories); } return lastChanged; } /** * Removes the specified repository from the database * * @param info the repository to be removed * @return The date/time the removal occurred * @throws ServiceException */ private Date doRemove(RepositoryInfo info) throws ServiceException { Set<String> related = info.getPullsFrom(); related.addAll(info.getPushesTo()); CommitDAO commitDao = new CommitDAO(); MongoLabProvider.deleteRepository(info.getId()); commitDao.removeRepositoryFromAllCommits(info.getSystemName(), info.getId()); for (String id : related) { try { deleteRepository(info.getSystemName(), id, false); } catch (RepositoryReferencedException re) { LoggerFactory.getLogger(TopologyDAO.class).warn("Repository <" + id + ">, referenced by <" + info.getId() + "> could not be deleted from the topology, because it is still referenced."); } catch (ServiceException se) { LoggerFactory.getLogger(TopologyDAO.class).warn("Repository <" + id + ">, referenced by <" + info.getId() + "> could not be deleted from the topology, due to the following error:", se); } } commitDao.deleteOrphanedCommits(info.getSystemName()); return DateUtil.getLocalTimeInUTC(); } }