package codeine; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadPoolExecutor; import javax.inject.Inject; import org.apache.log4j.Logger; import codeine.configuration.ConfigurationReadManagerServer; import codeine.configuration.NodeMonitor; import codeine.configuration.PathHelper; import codeine.db.ProjectsConfigurationConnector; import codeine.db.mysql.connectors.ProjectConfigurationDatabaseConnectorListProvider; import codeine.executer.ThreadPoolUtils; import codeine.jsons.collectors.CollectorInfo; import codeine.jsons.collectors.CollectorInfo.CollectorType; import codeine.jsons.project.ProjectJson; import codeine.model.Constants; import codeine.utils.ExceptionUtils; import codeine.utils.FilesUtils; import codeine.utils.JsonFileUtils; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; public class ConfigurationManagerServer extends ConfigurationReadManagerServer { private static final Logger log = Logger.getLogger(ConfigurationManagerServer.class); private static final int MAX_NUM_OF_DB_ENTRIES = 30; private static final int NUM_OF_THREADS_FOR_EACH_DB = 1; private ProjectConfigurationInPeerUpdater projectsUpdater; private PathHelper pathHelper; private JsonFileUtils jsonFileUtils; private ProjectConfigurationDatabaseConnectorListProvider statusDatabaseConnectorListProvider; private Cache<String, ThreadPoolExecutor> dbUpdateThreadsMap = CacheBuilder.newBuilder().maximumSize(MAX_NUM_OF_DB_ENTRIES).build(); @Inject public ConfigurationManagerServer(JsonFileUtils jsonFileUtils, PathHelper pathHelper, ProjectConfigurationInPeerUpdater projectsUpdater, ProjectConfigurationDatabaseConnectorListProvider statusDatabaseConnectorListProvider) { super(jsonFileUtils, pathHelper); this.jsonFileUtils = jsonFileUtils; this.pathHelper = pathHelper; this.projectsUpdater = projectsUpdater; this.statusDatabaseConnectorListProvider = statusDatabaseConnectorListProvider; } public void deleteProject(final ProjectJson projectToDelete) { String dirName = pathHelper.getProjectsDir() + "/" + projectToDelete.name(); FilesUtils.delete(dirName); projects().remove(projectToDelete.name()); for (final ProjectsConfigurationConnector projectsConfigurationConnector : statusDatabaseConnectorListProvider.get()) { getUpdateThreadPool(projectsConfigurationConnector.getKey()).execute(new Runnable() { @Override public void run() { try { projectsConfigurationConnector.deleteProject(projectToDelete); } catch (Exception e) { log.warn("cannot update project in database " + projectToDelete.name() + " " + projectsConfigurationConnector, e); } } }); } } private ThreadPoolExecutor getUpdateThreadPool(String key) { try { return dbUpdateThreadsMap.get(key, new Callable<ThreadPoolExecutor>() { @Override public ThreadPoolExecutor call() throws Exception { return ThreadPoolUtils.newThreadPool(NUM_OF_THREADS_FOR_EACH_DB, "ConfigurationManagerServer-DB-Update"); } }); } catch (ExecutionException e) { throw ExceptionUtils.asUnchecked(e); } } public boolean updateProject(final ProjectJson updatedProject) { log.info("updating project " + updatedProject); changeMonitorsToCollectors(updatedProject); String file = pathHelper.getProjectsDir() + "/" + updatedProject.name() + "/" + Constants.PROJECT_CONF_FILE; jsonFileUtils.setContent(file, updatedProject); final ProjectJson previousProject = projects().put(updatedProject.name(), updatedProject); log.info("updating project in db and peers " + updatedProject.name()); updateProjectInDb(updatedProject); projectsUpdater.updatePeers(updatedProject, previousProject); return null != previousProject; } private void changeMonitorsToCollectors(ProjectJson updatedProject) { for (NodeMonitor monitorInfo : updatedProject.monitors()) { String name = monitorInfo.name(); CollectorType type = CollectorType.Monitor; CollectorInfo collectorInfo = new CollectorInfo(name, monitorInfo.script_content(), monitorInfo.minInterval(), monitorInfo.credentials(), type, monitorInfo.notification_enabled()); updatedProject.collectors().add(collectorInfo); } updatedProject.monitors().clear(); } public void updateDb() { for (ProjectJson project : projects().values()) { updateProjectInDb(project); } projectsUpdater.updateAllPeers(); } public void updateDb(String serverKey) { ProjectsConfigurationConnector projectsConfigurationConnector = getConnector(serverKey); for (ProjectJson project : projects().values()) { updateProjectInDb(project, projectsConfigurationConnector); } } private ProjectsConfigurationConnector getConnector(String serverKey) { for (final ProjectsConfigurationConnector projectsConfigurationConnector : statusDatabaseConnectorListProvider.get()) { if (projectsConfigurationConnector.getKey().equals(serverKey)) { return projectsConfigurationConnector; } } throw new IllegalArgumentException("server not found " + serverKey); } private void updateProjectInDb(final ProjectJson project) { for (final ProjectsConfigurationConnector projectsConfigurationConnector : statusDatabaseConnectorListProvider.get()) { updateProjectInDb(project, projectsConfigurationConnector); } } private void updateProjectInDb(final ProjectJson project, final ProjectsConfigurationConnector projectsConfigurationConnector) { getUpdateThreadPool(projectsConfigurationConnector.getKey()).execute(new Runnable() { @Override public void run() { try { projectsConfigurationConnector.updateProject(project); } catch (Exception e) { log.warn("cannot update project in database " + project.name() + " " + projectsConfigurationConnector, e); } } }); } public void createNewProject(ProjectJson project) { String dir = pathHelper.getProjectsDir() + "/" + project.name(); if (FilesUtils.exists(dir)) { throw new RuntimeException("project '"+ project.name() + "' already exists"); } log.info("creating project in " + dir); FilesUtils.mkdirs(dir); updateProject(project); } public ProjectJson reloadProject(String projectName) { ProjectJson project = getProjectFromDisk(projectName); final ProjectJson previousProject = projects().put(projectName, project); log.info("updating project in db and peers " + projectName); updateProjectInDb(project); projectsUpdater.updatePeers(project, previousProject); return project; } }