package rocks.inspectit.ui.rcp.repository; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.collections.CollectionUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.ui.progress.IProgressConstants; import rocks.inspectit.shared.all.cmr.model.PlatformIdent; import rocks.inspectit.ui.rcp.InspectIT; import rocks.inspectit.ui.rcp.InspectITImages; import rocks.inspectit.ui.rcp.preferences.PreferencesUtils; import rocks.inspectit.ui.rcp.util.ListenerList; /** * The repository manager only for {@link CmrRepositoryDefinition}s. * * @author Ivan Senic * */ public class CmrRepositoryManager { /** * /** Update online repository status job repetition time in milliseconds. */ public static final long UPDATE_JOB_REPETITION = 60000; /** * The list containing the available {@link RepositoryDefinition} objects. */ private List<CmrRepositoryDefinition> cmrRepositoryDefinitions = new ArrayList<>(); /** * The list of listeners to be notified. */ private ListenerList<CmrRepositoryChangeListener> cmrRepositoryChangeListeners = new ListenerList<>(); /** * Map of jobs. */ private Map<CmrRepositoryDefinition, UpdateRepositoryJob> repositoryUpdateJobMap = new ConcurrentHashMap<>(); /** * Default constructor. * <p> * Loads the repository definitions from the preference store. */ public CmrRepositoryManager() { List<CmrRepositoryDefinition> savedCmrs = PreferencesUtils.getCmrRepositoryDefinitions(); if (CollectionUtils.isNotEmpty(savedCmrs)) { cmrRepositoryDefinitions.addAll(savedCmrs); for (CmrRepositoryDefinition cmrRepositoryDefinition : cmrRepositoryDefinitions) { for (CmrRepositoryChangeListener repositoryChangeListener : cmrRepositoryChangeListeners) { cmrRepositoryDefinition.addCmrRepositoryChangeListener(repositoryChangeListener); } UpdateRepositoryJob updateRepositoryJob = new UpdateRepositoryJob(cmrRepositoryDefinition, true); updateRepositoryJob.schedule(); repositoryUpdateJobMap.put(cmrRepositoryDefinition, updateRepositoryJob); } } } /** * Adds a repository definition handled by this manager. * * @param cmrRepositoryDefinition * The definition to add. */ public void addCmrRepositoryDefinition(CmrRepositoryDefinition cmrRepositoryDefinition) { if (!cmrRepositoryDefinitions.contains(cmrRepositoryDefinition)) { for (CmrRepositoryChangeListener repositoryChangeListener : cmrRepositoryChangeListeners) { cmrRepositoryDefinition.addCmrRepositoryChangeListener(repositoryChangeListener); } cmrRepositoryDefinitions.add(cmrRepositoryDefinition); savePreference(); for (CmrRepositoryChangeListener repositoryChangeListener : cmrRepositoryChangeListeners) { repositoryChangeListener.repositoryAdded(cmrRepositoryDefinition); } UpdateRepositoryJob updateRepositoryJob = new UpdateRepositoryJob(cmrRepositoryDefinition, true); updateRepositoryJob.schedule(); repositoryUpdateJobMap.put(cmrRepositoryDefinition, updateRepositoryJob); } } /** * Removes a repository definition and notifies all registered listeners. * * @param cmrRepositoryDefinition * The definition to remove. */ public void removeCmrRepositoryDefinition(CmrRepositoryDefinition cmrRepositoryDefinition) { for (CmrRepositoryChangeListener repositoryChangeListener : cmrRepositoryChangeListeners) { cmrRepositoryDefinition.removeCmrRepositoryChangeListener(repositoryChangeListener); } cmrRepositoryDefinitions.remove(cmrRepositoryDefinition); savePreference(); for (CmrRepositoryChangeListener repositoryChangeListener : cmrRepositoryChangeListeners) { repositoryChangeListener.repositoryRemoved(cmrRepositoryDefinition); } UpdateRepositoryJob updateRepositoryJob = repositoryUpdateJobMap.remove(cmrRepositoryDefinition); if (null != updateRepositoryJob) { updateRepositoryJob.cancel(); } } /** * Forces the CMR Online update check. If the {@link CmrRepositoryDefinition} to check is not on * the current list of repositories, this method will create a small job to check online status, * but this job won't be rescheduled. * * @param cmrRepositoryDefinition * {@link CmrRepositoryDefinition}. * @return Returns the job that will be performing the update. Caller can use this job to react * on the job being done. */ public UpdateRepositoryJob forceCmrRepositoryOnlineStatusUpdate(final CmrRepositoryDefinition cmrRepositoryDefinition) { UpdateRepositoryJob updateRepositoryJob = repositoryUpdateJobMap.get(cmrRepositoryDefinition); if (null != updateRepositoryJob) { if (updateRepositoryJob.cancel()) { updateRepositoryJob.schedule(); } } return updateRepositoryJob; } /** * Forces update of all repositories. * * @return Returns the collection of jobs that will be performing the update. Caller can use * these jobs to react on the one or more jobs being done. */ public Collection<UpdateRepositoryJob> forceAllCmrRepositoriesOnlineStatusUpdate() { List<UpdateRepositoryJob> jobs = new ArrayList<>(); for (CmrRepositoryDefinition cmrRepositoryDefinition : cmrRepositoryDefinitions) { jobs.add(this.forceCmrRepositoryOnlineStatusUpdate(cmrRepositoryDefinition)); } return jobs; } /** * Returns all registered repository definitions handled by this manager. The list is * unmodifiable. * * @return The list of repository definitions. */ public List<CmrRepositoryDefinition> getCmrRepositoryDefinitions() { return Collections.unmodifiableList(cmrRepositoryDefinitions); } /** * Adds a listener which notifies on certain events. * * @param repositoryChangeListener * The listener to add. */ public void addCmrRepositoryChangeListener(CmrRepositoryChangeListener repositoryChangeListener) { cmrRepositoryChangeListeners.add(repositoryChangeListener); for (CmrRepositoryDefinition cmrRepositoryDefinition : cmrRepositoryDefinitions) { cmrRepositoryDefinition.addCmrRepositoryChangeListener(repositoryChangeListener); } } /** * Removes the listener. * * @param repositoryChangeListener * The listener to remove. */ public void removeCmrRepositoryChangeListener(CmrRepositoryChangeListener repositoryChangeListener) { cmrRepositoryChangeListeners.remove(repositoryChangeListener); for (CmrRepositoryDefinition cmrRepositoryDefinition : cmrRepositoryDefinitions) { cmrRepositoryDefinition.removeCmrRepositoryChangeListener(repositoryChangeListener); } } /** * Cancels all the update repository jobs. The method will return only when all jobs are * canceled. */ public void cancelAllUpdateRepositoriesJobs() { for (UpdateRepositoryJob updateRepositoryJob : repositoryUpdateJobMap.values()) { while (!updateRepositoryJob.cancel()) { try { updateRepositoryJob.join(); } catch (InterruptedException e) { break; } } } } /** * Updates the {@link CmrRepositoryDefinition} entry in the preferences. * * @param cmrRepositoryDefinition * Repository to update. */ public void updateCmrRepositoryDefinitionData(CmrRepositoryDefinition cmrRepositoryDefinition) { this.savePreference(); for (CmrRepositoryChangeListener listener : cmrRepositoryChangeListeners) { listener.repositoryDataUpdated(cmrRepositoryDefinition); } } /** * Informs all listener that the provided agent on the repository has been deleted. * * @param cmrRepositoryDefinition * the repository definition. * @param agent * Agent that was deleted. */ public void repositoryAgentDeleted(CmrRepositoryDefinition cmrRepositoryDefinition, PlatformIdent agent) { for (CmrRepositoryChangeListener listener : cmrRepositoryChangeListeners) { listener.repositoryAgentDeleted(cmrRepositoryDefinition, agent); } } /** * Save the preferences to the backend store. */ private void savePreference() { List<CmrRepositoryDefinition> toSave = new ArrayList<>(); for (CmrRepositoryDefinition repositoryDefinition : cmrRepositoryDefinitions) { toSave.add(repositoryDefinition); } PreferencesUtils.saveCmrRepositoryDefinitions(toSave, false); } /** * Update online status of all repositories job. * * @author Ivan Senic * */ public static class UpdateRepositoryJob extends Job { /** * CMR to update. */ private CmrRepositoryDefinition cmrRepositoryDefinition; /** * Should job be rescheduled after its execution. */ private boolean rescheduleJob; /** * Default constructor. * * @param cmrRepositoryDefinition * {@link CmrRepositoryDefinition} to update. * @param rescheduleJob * If job should be rescheduled after execution. */ public UpdateRepositoryJob(CmrRepositoryDefinition cmrRepositoryDefinition, boolean rescheduleJob) { super("Updating online status of CMR repository " + cmrRepositoryDefinition.getIp() + ":" + cmrRepositoryDefinition.getPort()); this.cmrRepositoryDefinition = cmrRepositoryDefinition; this.rescheduleJob = rescheduleJob; this.setUser(false); this.setProperty(IProgressConstants.ICON_PROPERTY, InspectIT.getDefault().getImageDescriptor(InspectITImages.IMG_SERVER_REFRESH_SMALL)); } /** * {@inheritDoc} */ @Override protected IStatus run(IProgressMonitor monitor) { try { cmrRepositoryDefinition.refreshOnlineStatus(); return Status.OK_STATUS; } finally { if (rescheduleJob) { this.schedule(UPDATE_JOB_REPETITION); } } } /** * @return the cmrRepositoryDefinition */ public CmrRepositoryDefinition getCmrRepositoryDefinition() { return cmrRepositoryDefinition; } } }