Mercurial > hg > release > thermostat-0.6
changeset 909:2930e0c260cc
Merge
author | Elliott Baron <ebaron@redhat.com> |
---|---|
date | Mon, 14 Jan 2013 14:04:50 -0500 |
parents | 1e51015e63e5 (current diff) b1b81446c892 (diff) |
children | 421d8a954893 |
files | agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBConfig.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBOptionParser.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBStartupConfiguration.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/MongoProcessRunner.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StalePidFileException.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageAlreadyRunningException.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStartException.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStopException.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/StorageCommand.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/StorageCommandTest.java bundles/pom.xml bundles/src/main/java/com/redhat/thermostat/bundles/OSGiRegistry.java bundles/src/main/java/com/redhat/thermostat/bundles/impl/Activator.java bundles/src/main/java/com/redhat/thermostat/bundles/impl/BundleLoader.java bundles/src/main/java/com/redhat/thermostat/bundles/impl/OSGiRegistryImpl.java bundles/src/test/java/com/redhat/thermostat/bundles/OSGiRegistryTest.java bundles/src/test/java/com/redhat/thermostat/bundles/impl/BundleLoaderTest.java bundles/src/test/java/com/redhat/thermostat/bundles/impl/OSGiRegistryImplTest.java common/core/src/main/java/com/redhat/thermostat/test/MockQuery.java distribution/pom.xml storage/core/src/main/java/com/redhat/thermostat/storage/model/AgentIdPojo.java web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java |
diffstat | 147 files changed, 4083 insertions(+), 3427 deletions(-) [+] |
line wrap: on
line diff
--- a/agent/cli/pom.xml Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/pom.xml Mon Jan 14 14:04:50 2013 -0500 @@ -106,7 +106,7 @@ <Private-Package> com.redhat.thermostat.agent.cli.impl, com.redhat.thermostat.agent.cli.impl.locale, - com.redhat.thermostat.agent.cli.db, + com.redhat.thermostat.agent.cli.impl.db, </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses>
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBConfig.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import com.redhat.thermostat.agent.cli.impl.StorageCommand; - -/** - * Set of configuration option that the {@link StorageCommand} understands. - */ -public enum DBConfig { - - BIND, - PORT, - -}
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBOptionParser.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.config.ThermostatOptionParser; -import com.redhat.thermostat.common.locale.Translate; -import com.redhat.thermostat.common.tools.ApplicationState; - -public class DBOptionParser implements ThermostatOptionParser { - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - - private boolean quiet; - - private DBStartupConfiguration configuration; - - private Arguments args; - - private DBArgs serviceAction; - - private boolean dryRun; - - public DBOptionParser(DBStartupConfiguration configuration, Arguments args) { - this.args = args; - this.configuration = configuration; - } - - @Override - public void parse() throws InvalidConfigurationException { - - if (args.hasArgument(DBArgs.START.option)) { - serviceAction = DBArgs.START; - } else if (args.hasArgument(DBArgs.STOP.option)) { - serviceAction = DBArgs.STOP; - } else { - throw new InvalidConfigurationException(translator.localize(LocaleResources.COMMAND_STORAGE_ARGUMENT_REQUIRED)); - } - - if (args.hasArgument(DBArgs.DRY.option)) { - dryRun = true; - } - - if (args.hasArgument(DBArgs.QUIET.option)) { - quiet = true; - } - - // leave at the end, since it depends on the previous settings - String address = configuration.getBindIP(); - long port = configuration.getPort(); - configuration.setDBConnectionString("mongodb://" + address + ":" + port); - } - - public boolean isDryRun() { - return dryRun; - } - - public ApplicationState getAction() { - return serviceAction.state; - } - - static enum DBArgs { - - DRY("dryRun", ApplicationState.NONE), - - HELP("help", ApplicationState.HELP), - - START("start", ApplicationState.START), - STOP("stop", ApplicationState.STOP), - - QUIET("quiet", ApplicationState.NONE); - - private String option; - private ApplicationState state; - - DBArgs(String option, ApplicationState state) { - this.option = option; - this.state = state; - } - } - - public boolean isQuiet() { - return quiet; - } -}
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/DBStartupConfiguration.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import java.io.File; - -import com.redhat.thermostat.common.config.ConfigUtils; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.storage.config.StartupConfiguration; - -public class DBStartupConfiguration implements StartupConfiguration { - - private File dbPath; - private File logFile; - private File pidFile; - - private long localPort; - - private String dbConnectionString; - - private String ip; - - public DBStartupConfiguration() throws InvalidConfigurationException { - dbPath = ConfigUtils.getStorageDirectory(); - logFile = ConfigUtils.getStorageLogFile(); - pidFile = ConfigUtils.getStoragePidFile(); - } - - public File getDBPath() { - return dbPath; - } - - public File getLogFile() { - return logFile; - } - - public File getPidFile() { - return pidFile; - } - - public void setPort(long localPort) { - this.localPort = localPort; - } - - public long getPort() { - return localPort; - } - - void setDBConnectionString(String dbConnectionString) { - this.dbConnectionString = dbConnectionString; - } - - @Override - public String getDBConnectionString() { - return dbConnectionString; - } - - public void setBindIP(String ip) { - this.ip = ip; - } - - public String getBindIP() { - return ip; - } -} \ No newline at end of file
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/MongoProcessRunner.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,236 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.db; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.locale.Translate; -import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.utils.LoggedExternalProcess; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.service.process.UnixProcessUtilities; - -public class MongoProcessRunner { - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - private static final Logger logger = LoggingUtils.getLogger(MongoProcessRunner.class); - - private static final String MONGO_PROCESS = "mongod"; - - private static final String [] MONGO_BASIC_ARGS = { - "mongod", "--quiet", "--fork", "--auth", "--nohttpinterface", "--bind_ip" - }; - - private static final String [] MONGO_SHUTDOWN_ARGS = { - "kill", "-s", "TERM" - }; - - private static final String NO_JOURNAL_ARGUMENT = "--nojournal"; - private static final String NO_JOURNAL_FIRST_VERSION = "1.9.2"; - - private DBStartupConfiguration configuration; - private boolean isQuiet; - - public MongoProcessRunner(DBStartupConfiguration configuration, boolean quiet) { - this.configuration = configuration; - this.isQuiet = quiet; - } - - private String getPid() { - - String pid = null; - - File pidfile = configuration.getPidFile(); - Charset charset = Charset.defaultCharset(); - if (pidfile.exists()) { - try (BufferedReader reader = Files.newBufferedReader(pidfile.toPath(), charset)) { - pid = reader.readLine(); - if (pid == null || pid.isEmpty()) { - pid = null; - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Exception while reading pid file", ex); - pid = null; - } - } - - return pid; - } - - public void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { - - List<String> commands = new ArrayList<>(Arrays.asList(MONGO_SHUTDOWN_ARGS)); - commands.add(getPid()); - - LoggedExternalProcess process = new LoggedExternalProcess(commands); - int status = process.runAndReturnResult(); - if (status == 0) { - display(translator.localize(LocaleResources.SERVER_SHUTDOWN_COMPLETE, configuration.getDBPath().toString())); - display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); - - } else { - - String message = translator.localize(LocaleResources.CANNOT_SHUTDOWN_SERVER, - configuration.getDBPath().toString(), - String.valueOf(status)); - display(message); - throw new StorageStopException(configuration.getDBPath(), status, message); - } - } - - private boolean checkExistingProcess() { - String pid = getPid(); - if (pid == null) - return false; - - String processName = UnixProcessUtilities.getInstance().getProcessName(getPid()); - // TODO: check if we want mongos or mongod from the configs - return processName != null && processName.equalsIgnoreCase(MONGO_PROCESS); - } - - public void startService() throws IOException, InterruptedException, ApplicationException { - - String pid = getPid(); - if (pid != null) { - String message = null; - ApplicationException ex = null; - if (!checkExistingProcess()) { - message = translator.localize(LocaleResources.STALE_PID_FILE_NO_MATCHING_PROCESS, configuration.getPidFile().toString(), MONGO_PROCESS); - ex = new StalePidFileException(configuration.getPidFile()); - } else { - message = translator.localize(LocaleResources.STORAGE_ALREADY_RUNNING_WITH_PID, String.valueOf(pid)); - ex = new StorageAlreadyRunningException(Integer.valueOf(pid), message); - } - - display(message); - throw ex; - } - - List<String> commands = new ArrayList<>(Arrays.asList(MONGO_BASIC_ARGS)); - String dbVersion = getDBVersion(); - if (dbVersion.compareTo(NO_JOURNAL_FIRST_VERSION) >= 0) { - commands.add(1, NO_JOURNAL_ARGUMENT); - } - - // check that the db directory exist - display(translator.localize(LocaleResources.STARTING_STORAGE_SERVER)); - - commands.add(configuration.getBindIP()); - - commands.add("--dbpath"); - commands.add(configuration.getDBPath().getCanonicalPath()); - - commands.add("--logpath"); - commands.add(configuration.getLogFile().getCanonicalPath()); - - commands.add("--pidfilepath"); - commands.add(configuration.getPidFile().getCanonicalPath()); - - commands.add("--port"); - commands.add(Long.toString(configuration.getPort())); - - LoggedExternalProcess process = new LoggedExternalProcess(commands); - int status = -1; - try { - status = process.runAndReturnResult(); - } catch (ApplicationException ae) { - String message = translator.localize(LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); - display(message); - throw ae; - } - - Thread.sleep(500); - - if (status == 0) { - pid = getPid(); - if (pid == null) status = -1; - } - - if (status == 0) { - display(translator.localize(LocaleResources.SERVER_LISTENING_ON, configuration.getDBConnectionString())); - display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); - display(translator.localize(LocaleResources.PID_IS, String.valueOf(pid))); - - } else { - - String message = translator.localize(LocaleResources.CANNOT_START_SERVER, - configuration.getDBPath().toString(), - String.valueOf(status)); - display(message); - throw new StorageStartException(configuration.getDBPath(), status, message); - } - } - - private String getDBVersion() throws IOException { - Process process; - try { - process = new ProcessBuilder(Arrays.asList("mongod", "--version")) - .start(); - } catch (IOException e) { - String message = translator.localize( - LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); - display(message); - throw e; - } - InputStream out = process.getInputStream(); - InputStreamReader reader = new InputStreamReader(out); - BufferedReader bufReader = new BufferedReader(reader); - String firstLine = bufReader.readLine(); - int commaIdx = firstLine.indexOf(",", 12); - String versionString = firstLine.substring(12, commaIdx); - return versionString; - } - - private void display(String message) { - if (!isQuiet) { - System.out.println(message); - } - } -}
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StalePidFileException.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ -package com.redhat.thermostat.agent.cli.db; - -import java.io.File; - -import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.common.locale.Translate; -import com.redhat.thermostat.common.tools.ApplicationException; - -public class StalePidFileException extends ApplicationException { - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - - private final File pidFile; - - public StalePidFileException(File pidFile) { - super(translator.localize(LocaleResources.STALE_PID_FILE, pidFile.toString())); - this.pidFile = pidFile; - } - - public File getPidFile() { - return pidFile; - } - -}
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageAlreadyRunningException.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ -package com.redhat.thermostat.agent.cli.db; - -import com.redhat.thermostat.common.tools.ApplicationException; - -public class StorageAlreadyRunningException extends ApplicationException { - - private final int storagePid; - - public StorageAlreadyRunningException(int pid, String message) { - super(message); - storagePid = pid; - } - - public int getStoragePid() { - return storagePid; - } - -}
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStartException.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ -package com.redhat.thermostat.agent.cli.db; - -import java.io.File; - -import com.redhat.thermostat.common.tools.ApplicationException; - -public class StorageStartException extends ApplicationException { - - private final File dbFile; - private final int status; - - public StorageStartException(File dbPath, int status, String message) { - super(message); - this.dbFile = dbPath; - this.status = status; - } - - public File getDbPath() { - return dbFile; - } - - public int getStatus() { - return status; - } - -}
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/db/StorageStopException.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ -package com.redhat.thermostat.agent.cli.db; - -import java.io.File; - -import com.redhat.thermostat.common.tools.ApplicationException; - -public class StorageStopException extends ApplicationException { - - private final File dbConfig; - private final int status; - - public StorageStopException(File dbConfig, int status, String message) { - super(message); - this.dbConfig = dbConfig; - this.status = status; - } - - public File getDbConfig() { - return dbConfig; - } - - public int getStatus() { - return status; - } - -}
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,6 +41,7 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import com.redhat.thermostat.agent.cli.impl.db.StorageCommand; import com.redhat.thermostat.common.cli.CommandRegistry; import com.redhat.thermostat.common.cli.CommandRegistryImpl;
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java Mon Jan 14 14:04:50 2013 -0500 @@ -140,7 +140,9 @@ connection.connect(); logger.fine("Connecting to storage..."); + @SuppressWarnings("rawtypes") ServiceReference configServiceRef = bundleContext.getServiceReference(ConfigurationServer.class.getName()); + @SuppressWarnings("unchecked") final ConfigurationServer configServer = (ConfigurationServer) bundleContext.getService(configServiceRef); configServer.startListening(configuration.getConfigListenAddress());
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java Mon Jan 14 14:04:50 2013 -0500 @@ -40,7 +40,8 @@ import java.util.List; import java.util.concurrent.Semaphore; -import com.redhat.thermostat.agent.cli.db.StorageAlreadyRunningException; +import com.redhat.thermostat.agent.cli.impl.db.StorageAlreadyRunningException; +import com.redhat.thermostat.agent.cli.impl.db.StorageCommand; import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener;
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/StorageCommand.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.impl; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; - -import com.redhat.thermostat.agent.cli.db.DBConfig; -import com.redhat.thermostat.agent.cli.db.DBOptionParser; -import com.redhat.thermostat.agent.cli.db.DBStartupConfiguration; -import com.redhat.thermostat.agent.cli.db.MongoProcessRunner; -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.config.ConfigUtils; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.common.tools.BasicCommand; - -public class StorageCommand extends BasicCommand { - - private static final String NAME = "storage"; - - private DBStartupConfiguration configuration; - private DBOptionParser parser; - - private MongoProcessRunner runner; - - private void parseArguments(Arguments args) throws InvalidConfigurationException { - - this.configuration = new DBStartupConfiguration(); - // configs, read everything that is in the configs - File propertyFile = ConfigUtils.getStorageConfigurationFile(); - if (!propertyFile.exists()) { - throw new InvalidConfigurationException("can't access database configuration file " + - propertyFile); - } - readAndSetProperties(propertyFile); - - parser = new DBOptionParser(configuration, args); - parser.parse(); - } - - @Override - public void run(CommandContext ctx) throws CommandException { - - try { - parseArgsAndRun(ctx); - } catch (InvalidConfigurationException e) { - throw new CommandException(e); - } - } - - private void parseArgsAndRun(CommandContext ctx) - throws InvalidConfigurationException { - parseArguments(ctx.getArguments()); - - // dry run means we don't do anything at all - if (parser.isDryRun()) return; - - runner = createRunner(); - try { - switch (parser.getAction()) { - case START: - startService(); - break; - case STOP: - stopService(); - break; - default: - break; - } - getNotifier().fireAction(ApplicationState.SUCCESS); - } catch (Exception e) { - getNotifier().fireAction(ApplicationState.FAIL, e); - } - } - - private void readAndSetProperties(File propertyFile) throws InvalidConfigurationException { - - Properties properties = new Properties(); - try { - properties.load(new FileInputStream(propertyFile)); - - } catch (IOException e) { - throw new InvalidConfigurationException(e); - } - - if (properties.containsKey(DBConfig.PORT.name())) { - String port = (String) properties.get(DBConfig.PORT.name()); - int localPort = Integer.parseInt(port); - configuration.setPort(localPort); - } else { - throw new InvalidConfigurationException(DBConfig.PORT + " property missing"); - } - - if (properties.containsKey(DBConfig.BIND.name())) { - String ip = (String) properties.get(DBConfig.BIND.name()); - configuration.setBindIP(ip); - } else { - throw new InvalidConfigurationException(DBConfig.BIND + " property missing"); - } - } - - private void startService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { - runner.startService(); - getNotifier().fireAction(ApplicationState.START); - } - - - private void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { - check(); - runner.stopService(); - getNotifier().fireAction(ApplicationState.STOP); - } - - MongoProcessRunner createRunner() { - return new MongoProcessRunner(configuration, parser.isQuiet()); - } - - private void check() throws InvalidConfigurationException { - if (!configuration.getDBPath().exists() || - !configuration.getLogFile().getParentFile().exists() || - !configuration.getPidFile().getParentFile().exists()) - { - throw new InvalidConfigurationException("database directories do not exist..."); - } - } - - @Override - public DBStartupConfiguration getConfiguration() { - return configuration; - } - - @Override - public String getName() { - return NAME; - } - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBConfig.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,67 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + + +/** + * Set of configuration options that the {@link StorageCommand} understands. + * Keys map to properties in $THERMOSTAT_HOME/storage/db.properties. + */ +public enum DBConfig { + + /** + * The bind IP address. + */ + BIND, + /** + * The port on which mongodb will be listening. + */ + PORT, + /** + * Weather or not to start mongodb with SSL enabled. + */ + SSL_ENABLE, + /** + * The PEM encoded SSL certificate + SSL key. + */ + SSL_PEM_FILE, + /** + * The passphrase for the encrypted SSL key. Only used if the private key was encrypted. + */ + SSL_KEY_PASSWORD, + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBOptionParser.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,121 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import com.redhat.thermostat.common.cli.Arguments; +import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.config.ThermostatOptionParser; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.common.tools.ApplicationState; + +public class DBOptionParser implements ThermostatOptionParser { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private boolean quiet; + + private DBStartupConfiguration configuration; + + private Arguments args; + + private DBArgs serviceAction; + + private boolean dryRun; + + public DBOptionParser(DBStartupConfiguration configuration, Arguments args) { + this.args = args; + this.configuration = configuration; + } + + @Override + public void parse() throws InvalidConfigurationException { + + if (args.hasArgument(DBArgs.START.option)) { + serviceAction = DBArgs.START; + } else if (args.hasArgument(DBArgs.STOP.option)) { + serviceAction = DBArgs.STOP; + } else { + throw new InvalidConfigurationException(translator.localize(LocaleResources.COMMAND_STORAGE_ARGUMENT_REQUIRED)); + } + + if (args.hasArgument(DBArgs.DRY.option)) { + dryRun = true; + } + + if (args.hasArgument(DBArgs.QUIET.option)) { + quiet = true; + } + + // leave at the end, since it depends on the previous settings + String address = configuration.getBindIP(); + long port = configuration.getPort(); + configuration.setDBConnectionString("mongodb://" + address + ":" + port); + } + + public boolean isDryRun() { + return dryRun; + } + + public ApplicationState getAction() { + return serviceAction.state; + } + + static enum DBArgs { + + DRY("dryRun", ApplicationState.NONE), + + HELP("help", ApplicationState.HELP), + + START("start", ApplicationState.START), + STOP("stop", ApplicationState.STOP), + + QUIET("quiet", ApplicationState.NONE); + + private String option; + private ApplicationState state; + + DBArgs(String option, ApplicationState state) { + this.option = option; + this.state = state; + } + } + + public boolean isQuiet() { + return quiet; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfiguration.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,179 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.storage.config.StartupConfiguration; + +public class DBStartupConfiguration implements StartupConfiguration { + + private File dbPath; + private File logFile; + private File pidFile; + private boolean sslEnabled = false; + private File sslPemFile; + private String sslKeyPassphrase; + + private long localPort; + + private String dbConnectionString; + + private String ip; + + public DBStartupConfiguration(File properties, File dbPath, File logFile, + File pidFile) throws InvalidConfigurationException { + this.dbPath = dbPath; + this.logFile = logFile; + this.pidFile = pidFile; + readAndSetProperties(properties); + } + + public File getDBPath() { + return dbPath; + } + + public File getLogFile() { + return logFile; + } + + public File getPidFile() { + return pidFile; + } + + public void setPort(long localPort) { + this.localPort = localPort; + } + + public long getPort() { + return localPort; + } + + void setDBConnectionString(String dbConnectionString) { + this.dbConnectionString = dbConnectionString; + } + + @Override + public String getDBConnectionString() { + return dbConnectionString; + } + + void setBindIP(String ip) { + this.ip = ip; + } + + public String getBindIP() { + return ip; + } + + public boolean isSslEnabled() { + return sslEnabled; + } + + void setSslEnabled(boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + /** + * + * @return The file containing the server certificate and the private key in PEM format or null + * if nothing was specified in $THERMOSTAT_HOME/storage/db.properties. + */ + public File getSslPemFile() { + return sslPemFile; + } + + void setSslPemFile(File sslPemFile) { + this.sslPemFile = sslPemFile; + } + + /** + * + * @return The passphrase for the encrypted server key or null if config was + * not set. + */ + public String getSslKeyPassphrase() { + return sslKeyPassphrase; + } + + void setSslKeyPassphrase(String sslKeyPassphrase) { + this.sslKeyPassphrase = sslKeyPassphrase; + } + + private void readAndSetProperties(File propertyFile) throws InvalidConfigurationException { + + Properties properties = new Properties(); + try { + properties.load(new FileInputStream(propertyFile)); + + } catch (IOException e) { + throw new InvalidConfigurationException(e); + } + + if (properties.containsKey(DBConfig.PORT.name())) { + String port = (String) properties.get(DBConfig.PORT.name()); + int localPort = Integer.parseInt(port); + setPort(localPort); + } else { + throw new InvalidConfigurationException(DBConfig.PORT + " property missing"); + } + + if (properties.containsKey(DBConfig.BIND.name())) { + String ip = (String) properties.get(DBConfig.BIND.name()); + setBindIP(ip); + } else { + throw new InvalidConfigurationException(DBConfig.BIND + " property missing"); + } + + // optional config + String enableSSLConfig = properties.getProperty(DBConfig.SSL_ENABLE.name()); + setSslEnabled(Boolean.parseBoolean(enableSSLConfig)); + + String pemFile = properties.getProperty(DBConfig.SSL_PEM_FILE.name()); + if (pemFile != null) { + setSslPemFile(new File(pemFile)); + } + + String keyPassPhrase = properties.getProperty(DBConfig.SSL_KEY_PASSWORD.name()); + setSslKeyPassphrase(keyPassPhrase); + + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/MongoProcessRunner.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,266 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.common.tools.ApplicationException; +import com.redhat.thermostat.common.utils.LoggedExternalProcess; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.service.process.UnixProcessUtilities; + +public class MongoProcessRunner { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + private static final Logger logger = LoggingUtils.getLogger(MongoProcessRunner.class); + + private static final String MONGO_PROCESS = "mongod"; + + private static final String [] MONGO_BASIC_ARGS = { + "mongod", "--quiet", "--fork", "--auth", "--nohttpinterface", "--bind_ip" + }; + + private static final String [] MONGO_SHUTDOWN_ARGS = { + "kill", "-s", "TERM" + }; + + private static final String NO_JOURNAL_ARGUMENT = "--nojournal"; + private static final String NO_JOURNAL_FIRST_VERSION = "1.9.2"; + + private DBStartupConfiguration configuration; + private boolean isQuiet; + + public MongoProcessRunner(DBStartupConfiguration configuration, boolean quiet) { + this.configuration = configuration; + this.isQuiet = quiet; + } + + private String getPid() { + + String pid = null; + + File pidfile = configuration.getPidFile(); + Charset charset = Charset.defaultCharset(); + if (pidfile.exists()) { + try (BufferedReader reader = Files.newBufferedReader(pidfile.toPath(), charset)) { + pid = reader.readLine(); + if (pid == null || pid.isEmpty()) { + pid = null; + } + } catch (IOException ex) { + logger.log(Level.WARNING, "Exception while reading pid file", ex); + pid = null; + } + } + + return pid; + } + + public void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { + + List<String> commands = new ArrayList<>(Arrays.asList(MONGO_SHUTDOWN_ARGS)); + commands.add(getPid()); + + LoggedExternalProcess process = new LoggedExternalProcess(commands); + int status = process.runAndReturnResult(); + if (status == 0) { + display(translator.localize(LocaleResources.SERVER_SHUTDOWN_COMPLETE, configuration.getDBPath().toString())); + display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); + // all went well, make sure to remove pid file. + try { + Files.delete(configuration.getPidFile().toPath()); + } catch (IOException e) { + // ignore + } + } else { + + String message = translator.localize(LocaleResources.CANNOT_SHUTDOWN_SERVER, + configuration.getDBPath().toString(), + String.valueOf(status)); + display(message); + throw new StorageStopException(configuration.getDBPath(), status, message); + } + } + + private boolean checkExistingProcess() { + String pid = getPid(); + if (pid == null) + return false; + + String processName = UnixProcessUtilities.getInstance().getProcessName(getPid()); + // TODO: check if we want mongos or mongod from the configs + return processName != null && processName.equalsIgnoreCase(MONGO_PROCESS); + } + + public void startService() throws IOException, InterruptedException, + ApplicationException, InvalidConfigurationException { + + String pid = getPid(); + if (pid != null) { + String message = null; + if (!checkExistingProcess()) { + message = translator.localize(LocaleResources.STALE_PID_FILE_NO_MATCHING_PROCESS, configuration.getPidFile().toString(), MONGO_PROCESS); + // Mongo didn't remove its PID file? Work around the issue. Log + // the event, remove the stale pid file and continue. + logger.log(Level.WARNING, message); + try { + Files.delete(configuration.getPidFile().toPath()); + } catch (IOException benign) { + // ignore this benign error + } + } else { + message = translator.localize(LocaleResources.STORAGE_ALREADY_RUNNING_WITH_PID, String.valueOf(pid)); + display(message); + throw new StorageAlreadyRunningException(Integer.valueOf(pid), message); + } + } + + String dbVersion = getDBVersion(); + List<String> commands = null; + commands = getStartupCommand(dbVersion); + + display(translator.localize(LocaleResources.STARTING_STORAGE_SERVER)); + + LoggedExternalProcess process = new LoggedExternalProcess(commands); + int status = -1; + try { + status = process.runAndReturnResult(); + } catch (ApplicationException ae) { + String message = translator.localize(LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); + display(message); + throw ae; + } + + Thread.sleep(500); + + if (status == 0) { + pid = getPid(); + if (pid == null) status = -1; + } + + if (status == 0) { + display(translator.localize(LocaleResources.SERVER_LISTENING_ON, configuration.getDBConnectionString())); + display(translator.localize(LocaleResources.LOG_FILE_AT, configuration.getLogFile().toString())); + display(translator.localize(LocaleResources.PID_IS, String.valueOf(pid))); + + } else { + + String message = translator.localize(LocaleResources.CANNOT_START_SERVER, + configuration.getDBPath().toString(), + String.valueOf(status)); + display(message); + throw new StorageStartException(configuration.getDBPath(), status, message); + } + } + + List<String> getStartupCommand(String dbVersion) throws IOException, InvalidConfigurationException { + List<String> commands = new ArrayList<>(Arrays.asList(MONGO_BASIC_ARGS)); + + if (dbVersion.compareTo(NO_JOURNAL_FIRST_VERSION) >= 0) { + commands.add(1, NO_JOURNAL_ARGUMENT); + } + commands.add(configuration.getBindIP()); + + commands.add("--dbpath"); + commands.add(configuration.getDBPath().getCanonicalPath()); + + commands.add("--logpath"); + commands.add(configuration.getLogFile().getCanonicalPath()); + + commands.add("--pidfilepath"); + commands.add(configuration.getPidFile().getCanonicalPath()); + + commands.add("--port"); + commands.add(Long.toString(configuration.getPort())); + + if (configuration.isSslEnabled()) { + // check for configuration which has a chance of working :) + if (configuration.getSslPemFile() == null) { + throw new InvalidConfigurationException("No SSL PEM file specified!"); + } else if (configuration.getSslKeyPassphrase() == null) { + throw new InvalidConfigurationException("No SSL key passphrase set!"); + } + commands.add("--sslOnNormalPorts"); + commands.add("--sslPEMKeyFile"); + commands.add(configuration.getSslPemFile().getCanonicalPath()); + commands.add("--sslPEMKeyPassword"); + commands.add(configuration.getSslKeyPassphrase()); + } + + return commands; + } + + private String getDBVersion() throws IOException { + Process process; + try { + process = new ProcessBuilder(Arrays.asList("mongod", "--version")) + .start(); + } catch (IOException e) { + String message = translator.localize( + LocaleResources.CANNOT_EXECUTE_PROCESS, MONGO_PROCESS); + display(message); + throw e; + } + InputStream out = process.getInputStream(); + InputStreamReader reader = new InputStreamReader(out); + BufferedReader bufReader = new BufferedReader(reader); + String firstLine = bufReader.readLine(); + int commaIdx = firstLine.indexOf(",", 12); + String versionString = firstLine.substring(12, commaIdx); + return versionString; + } + + private void display(String message) { + if (!isQuiet) { + System.out.println(message); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StalePidFileException.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; + +import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StalePidFileException extends ApplicationException { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private final File pidFile; + + public StalePidFileException(File pidFile) { + super(translator.localize(LocaleResources.STALE_PID_FILE, pidFile.toString())); + this.pidFile = pidFile; + } + + public File getPidFile() { + return pidFile; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageAlreadyRunningException.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StorageAlreadyRunningException extends ApplicationException { + + private final int storagePid; + + public StorageAlreadyRunningException(int pid, String message) { + super(message); + storagePid = pid; + } + + public int getStoragePid() { + return storagePid; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommand.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,149 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; +import java.io.IOException; + +import com.redhat.thermostat.common.cli.Arguments; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.config.ConfigUtils; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.tools.ApplicationException; +import com.redhat.thermostat.common.tools.ApplicationState; +import com.redhat.thermostat.common.tools.BasicCommand; + +public class StorageCommand extends BasicCommand { + + private static final String NAME = "storage"; + + private DBStartupConfiguration configuration; + private DBOptionParser parser; + + private MongoProcessRunner runner; + + private void parseArguments(Arguments args) throws InvalidConfigurationException { + + File dbPath = ConfigUtils.getStorageDirectory(); + File logFile = ConfigUtils.getStorageLogFile(); + File pidFile = ConfigUtils.getStoragePidFile(); + File propertyFile = ConfigUtils.getStorageConfigurationFile(); + if (!propertyFile.exists()) { + throw new InvalidConfigurationException("can't access database configuration file " + + propertyFile); + } + // read everything that is in the configs + this.configuration = new DBStartupConfiguration(propertyFile, dbPath, logFile, pidFile); + parser = new DBOptionParser(configuration, args); + parser.parse(); + } + + @Override + public void run(CommandContext ctx) throws CommandException { + + try { + parseArgsAndRun(ctx); + } catch (InvalidConfigurationException e) { + throw new CommandException(e); + } + } + + private void parseArgsAndRun(CommandContext ctx) + throws InvalidConfigurationException { + parseArguments(ctx.getArguments()); + + // dry run means we don't do anything at all + if (parser.isDryRun()) return; + + runner = createRunner(); + try { + switch (parser.getAction()) { + case START: + startService(); + break; + case STOP: + stopService(); + break; + default: + break; + } + getNotifier().fireAction(ApplicationState.SUCCESS); + } catch (InvalidConfigurationException e) { + // rethrow + throw e; + } catch (Exception e) { + getNotifier().fireAction(ApplicationState.FAIL, e); + } + } + + private void startService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { + runner.startService(); + getNotifier().fireAction(ApplicationState.START); + } + + + private void stopService() throws IOException, InterruptedException, InvalidConfigurationException, ApplicationException { + check(); + runner.stopService(); + getNotifier().fireAction(ApplicationState.STOP); + } + + MongoProcessRunner createRunner() { + return new MongoProcessRunner(configuration, parser.isQuiet()); + } + + private void check() throws InvalidConfigurationException { + if (!configuration.getDBPath().exists() || + !configuration.getLogFile().getParentFile().exists() || + !configuration.getPidFile().getParentFile().exists()) + { + throw new InvalidConfigurationException("database directories do not exist..."); + } + } + + @Override + public DBStartupConfiguration getConfiguration() { + return configuration; + } + + @Override + public String getName() { + return NAME; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageStartException.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; + +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StorageStartException extends ApplicationException { + + private final File dbFile; + private final int status; + + public StorageStartException(File dbPath, int status, String message) { + super(message); + this.dbFile = dbPath; + this.status = status; + } + + public File getDbPath() { + return dbFile; + } + + public int getStatus() { + return status; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/db/StorageStopException.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ +package com.redhat.thermostat.agent.cli.impl.db; + +import java.io.File; + +import com.redhat.thermostat.common.tools.ApplicationException; + +@SuppressWarnings("serial") +public class StorageStopException extends ApplicationException { + + private final File dbConfig; + private final int status; + + public StorageStopException(File dbConfig, int status, String message) { + super(message); + this.dbConfig = dbConfig; + this.status = status; + } + + public File getDbConfig() { + return dbConfig; + } + + public int getStatus() { + return status; + } + +}
--- a/agent/cli/src/main/resources/com/redhat/thermostat/agent/cli/impl/strings.properties Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/main/resources/com/redhat/thermostat/agent/cli/impl/strings.properties Mon Jan 14 14:04:50 2013 -0500 @@ -10,7 +10,7 @@ CANNOT_START_SERVER = cannot start server {0}, exit status: {1}. Please check that your configuration is valid CANNOT_SHUTDOWN_SERVER = cannot shutdown server {0}, exit status: {1}. Please check that your configuration is valid STALE_PID_FILE = stale pid file: {0} -STALE_PID_FILE_NO_MATCHING_PROCESS = A stale pid file ({0}) is present but there is no matching {1} process. Please remove the file if it has been shut down +STALE_PID_FILE_NO_MATCHING_PROCESS = A stale pid file ({0}) is present but there is no matching {1} process. Removing stale pid file. STARTING_STORAGE_SERVER = starting storage server... CANNOT_EXECUTE_PROCESS = can not execute {0} process. is it installed? SERVER_LISTENING_ON = server listening on ip: {0}
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,6 +41,7 @@ import org.junit.Test; +import com.redhat.thermostat.agent.cli.impl.db.StorageCommand; import com.redhat.thermostat.common.cli.Command; import com.redhat.thermostat.test.StubBundleContext;
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -144,6 +144,7 @@ // FIXME test the rest of AgentApplication + @SuppressWarnings("serial") private static class ThatsAllThatWeCareAbout extends RuntimeException { }
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/StorageCommandTest.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,295 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.cli.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Collection; -import java.util.Properties; -import java.util.Random; -import java.util.concurrent.CountDownLatch; - -import junit.framework.Assert; - -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionGroup; -import org.apache.commons.cli.Options; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import com.redhat.thermostat.agent.cli.db.DBConfig; -import com.redhat.thermostat.agent.cli.db.DBStartupConfiguration; -import com.redhat.thermostat.agent.cli.db.MongoProcessRunner; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.cli.SimpleArguments; -import com.redhat.thermostat.common.config.InvalidConfigurationException; -import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.tools.ApplicationState; - -public class StorageCommandTest { - - private static final String PORT = "27518"; - private static final String BIND = "127.0.0.1"; - private static final String DB = "storage/db"; - - private String tmpDir; - - @Before - public void setup() { - // need to create a dummy config file for the test - try { - Random random = new Random(); - - tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar + - Math.abs(random.nextInt()) + File.separatorChar; - - System.setProperty("THERMOSTAT_HOME", tmpDir); - File base = new File(tmpDir + "storage"); - base.mkdirs(); - - File tmpConfigs = new File(base, "db.properties"); - - new File(base, "run").mkdirs(); - new File(base, "logs").mkdirs(); - new File(base, "db").mkdirs(); - - Properties props = new Properties(); - - props.setProperty(DBConfig.BIND.name(), BIND); - props.setProperty(DBConfig.PORT.name(), PORT); - - props.store(new FileOutputStream(tmpConfigs), "thermostat test properties"); - - } catch (IOException e) { - Assert.fail("cannot setup tests: " + e); - } - } - - @Test - public void testConfig() throws CommandException { - SimpleArguments args = new SimpleArguments(); - args.addArgument("quiet", null); - args.addArgument("start", null); - args.addArgument("dryRun", null); - CommandContext ctx = mock(CommandContext.class); - when(ctx.getArguments()).thenReturn(args); - - StorageCommand service = new StorageCommand() { - @Override - MongoProcessRunner createRunner() { - throw new AssertionError("dry run should never create an actual runner"); - } - }; - - service.run(ctx); - - DBStartupConfiguration conf = service.getConfiguration(); - - Assert.assertEquals(tmpDir + DB, conf.getDBPath().getPath()); - Assert.assertEquals(Integer.parseInt(PORT), conf.getPort()); - Assert.assertEquals("mongodb://" + BIND + ":" + PORT , conf.getDBConnectionString()); - } - - private StorageCommand prepareService(boolean startSuccess) throws IOException, - InterruptedException, InvalidConfigurationException, ApplicationException - { - final MongoProcessRunner runner = mock(MongoProcessRunner.class); - if (!startSuccess) { - doThrow(new ApplicationException("mock exception")).when(runner).startService(); - } - - // TODO: stop not tested yet, but be sure it's not called from the code - doThrow(new ApplicationException("mock exception")).when(runner).stopService(); - - StorageCommand service = new StorageCommand() { - @Override - MongoProcessRunner createRunner() { - return runner; - } - }; - - return service; - } - - @Test - public void testListeners() throws InterruptedException, IOException, ApplicationException, InvalidConfigurationException, CommandException - { - StorageCommand service = prepareService(true); - - final CountDownLatch latch = new CountDownLatch(2); - - final boolean[] result = new boolean[2]; - service.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = false; - latch.countDown(); - latch.countDown(); - break; - - case SUCCESS: - result[0] = true; - latch.countDown(); - break; - - case START: - result[1] = true; - latch.countDown(); - break; - } - } - }); - - service.run(prepareContext()); - latch.await(); - - Assert.assertTrue(result[0]); - Assert.assertTrue(result[1]); - } - - @Test - public void testListenersFail() throws InterruptedException, IOException, ApplicationException, CommandException, InvalidConfigurationException - { - StorageCommand service = prepareService(false); - - final CountDownLatch latch = new CountDownLatch(1); - final boolean[] result = new boolean[1]; - service.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - - case SUCCESS: - result[0] = false; - break; - } - latch.countDown(); - } - }); - - service.run(prepareContext()); - latch.await(); - - Assert.assertTrue(result[0]); - } - - private CommandContext prepareContext() { - SimpleArguments args = new SimpleArguments(); - args.addArgument("quiet", "--quiet"); - args.addArgument("start", "--start"); - CommandContext ctx = mock(CommandContext.class); - when(ctx.getArguments()).thenReturn(args); - return ctx; - } - - @Test - public void testName() { - StorageCommand dbService = new StorageCommand(); - String name = dbService.getName(); - assertEquals("storage", name); - } - - @Test - public void testDescAndUsage() { - StorageCommand dbService = new StorageCommand(); - assertNotNull(dbService.getDescription()); - assertNotNull(dbService.getUsage()); - } - - @Ignore - @Test - public void testOptions() { - StorageCommand dbService = new StorageCommand(); - Options options = dbService.getOptions(); - assertNotNull(options); - assertEquals(4, options.getOptions().size()); - - assertTrue(options.hasOption("dryRun")); - Option dry = options.getOption("dryRun"); - assertEquals("d", dry.getOpt()); - assertEquals("run the service in dry run mode", dry.getDescription()); - assertFalse(dry.isRequired()); - assertFalse(dry.hasArg()); - - assertTrue(options.hasOption("start")); - Option start = options.getOption("start"); - assertEquals("start the database", start.getDescription()); - assertFalse(start.isRequired()); - assertFalse(start.hasArg()); - - assertTrue(options.hasOption("stop")); - Option stop = options.getOption("stop"); - assertEquals("stop the database", stop.getDescription()); - assertFalse(stop.isRequired()); - assertFalse(stop.hasArg()); - - assertTrue(options.hasOption("quiet")); - Option quiet = options.getOption("quiet"); - assertEquals("q", quiet.getOpt()); - assertEquals("don't produce any output", quiet.getDescription()); - assertFalse(quiet.isRequired()); - assertFalse(quiet.hasArg()); - - OptionGroup startStop = options.getOptionGroup(start); - assertTrue(startStop.isRequired()); - @SuppressWarnings("unchecked") - Collection<Option> groupOpts = startStop.getOptions(); - assertEquals(2, groupOpts.size()); - assertTrue(groupOpts.contains(start)); - assertTrue(groupOpts.contains(stop)); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/DBStartupConfigurationTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,122 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.File; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.config.InvalidConfigurationException; + +public class DBStartupConfigurationTest { + + private File dbLogFile; + private File dbPidFile; + private File dbPath; + + @Before + public void setUp() { + dbLogFile = new File("db.log"); + dbPidFile = new File("db.pid"); + dbPath = new File("somepath"); + } + + @After + public void tearDown() { + dbLogFile = null; + dbPidFile = null; + dbPath = null; + } + + @Test + public void canGetConfigFromPropertiesFile() throws Exception { + File dbProps = new File(this.getClass().getResource("/testDbConfig.properties").getFile()); + DBStartupConfiguration dbConfig = new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile); + + assertEquals(dbLogFile.getAbsolutePath(), dbConfig.getLogFile().getAbsolutePath()); + assertEquals(dbPidFile.getAbsolutePath(), dbConfig.getPidFile().getAbsolutePath()); + assertEquals(dbPath.getAbsolutePath(), dbConfig.getDBPath().getAbsolutePath()); + assertEquals("127.0.0.1", dbConfig.getBindIP()); + assertEquals(27518, dbConfig.getPort()); + assertEquals(true, dbConfig.isSslEnabled()); + assertEquals("/path/to/some/pem/file.pem", dbConfig.getSslPemFile().getAbsolutePath()); + assertEquals("somepassword", dbConfig.getSslKeyPassphrase()); + } + + @Test + public void canGetConfigFromPropertiesFile2() throws Exception { + File dbProps = new File(this.getClass().getResource("/testDbConfig2.properties").getFile()); + DBStartupConfiguration dbConfig = new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile); + + assertEquals(dbLogFile.getAbsolutePath(), dbConfig.getLogFile().getAbsolutePath()); + assertEquals(dbPidFile.getAbsolutePath(), dbConfig.getPidFile().getAbsolutePath()); + assertEquals(dbPath.getAbsolutePath(), dbConfig.getDBPath().getAbsolutePath()); + assertEquals("127.0.0.1", dbConfig.getBindIP()); + assertEquals(27518, dbConfig.getPort()); + assertEquals(false, dbConfig.isSslEnabled()); + assertNull(dbConfig.getSslPemFile()); + assertNull(dbConfig.getSslKeyPassphrase()); + } + + @Test + public void missingBindThrowsConfigException() throws Exception { + File dbProps = new File(this.getClass().getResource("/brokenDbConfig.properties").getFile()); + try { + new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile); + fail("BIND was not specified in properties file"); + } catch (InvalidConfigurationException e) { + assertEquals("BIND property missing", e.getMessage()); + } + } + + @Test + public void missingPortThrowsConfigException() throws Exception { + File dbProps = new File(this.getClass().getResource("/brokenDbConfig2.properties").getFile()); + try { + new DBStartupConfiguration(dbProps, dbPath, dbLogFile, dbPidFile); + fail("PORT was not specified in properties file"); + } catch (InvalidConfigurationException e) { + assertEquals("PORT property missing", e.getMessage()); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/MongoProcessRunnerTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,123 @@ +package com.redhat.thermostat.agent.cli.impl.db; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.agent.cli.impl.db.MongoProcessRunner; +import com.redhat.thermostat.common.config.InvalidConfigurationException; + +public class MongoProcessRunnerTest { + + private MongoProcessRunner runner; + private DBStartupConfiguration config; + private static final String NO_JOURNAL_MONGODB_VERSION = "2.0.0"; + private static final String JOURNAL_MONGODB_VERSION = "1.8.0"; + private static final String BIND_IP = "127.0.0.1"; + private static final long PORT = 12456; + + @Before + public void setUp() { + File dbPath = new File("/path/to/db"); + File logPath = new File("/path/to/log"); + File pidFile = new File("/path/to/pid"); + config = mock(DBStartupConfiguration.class); + when(config.getBindIP()).thenReturn(BIND_IP); + when(config.getPort()).thenReturn(PORT); + when(config.getDBPath()).thenReturn(dbPath); + when(config.getLogFile()).thenReturn(logPath); + when(config.getPidFile()).thenReturn(pidFile); + runner = new MongoProcessRunner(config, false); + } + + @After + public void tearDown() { + runner = null; + config = null; + } + + @Test + public void testCommandArgumentsWithJournalVersion() throws Exception { + String[] expected = { "mongod", "--nojournal", "--quiet", "--fork", + "--auth", "--nohttpinterface", "--bind_ip", config.getBindIP(), + "--dbpath", config.getDBPath().getCanonicalPath(), "--logpath", + config.getLogFile().getCanonicalPath(), "--pidfilepath", + config.getPidFile().getCanonicalPath(), "--port", + Long.toString(config.getPort()) }; + List<String> cmds = runner.getStartupCommand(NO_JOURNAL_MONGODB_VERSION); + String[] actual = cmds.toArray(new String[0]); + verifyEquals(expected, actual); + } + + @Test + public void testCommandArgumentsWithNoJournalVersion() throws Exception { + String[] expected = { "mongod", "--quiet", "--fork", "--auth", + "--nohttpinterface", "--bind_ip", config.getBindIP(), + "--dbpath", config.getDBPath().getCanonicalPath(), "--logpath", + config.getLogFile().getCanonicalPath(), "--pidfilepath", + config.getPidFile().getCanonicalPath(), "--port", + Long.toString(config.getPort()) }; + List<String> cmds = runner.getStartupCommand(JOURNAL_MONGODB_VERSION); + String[] actual = cmds.toArray(new String[0]); + verifyEquals(expected, actual); + } + + @Test + public void testCommandArgumentsWithSSLEnabled() throws Exception { + when(config.isSslEnabled()).thenReturn(true); + File pemFile = new File("/path/to/cert_and_key.pem"); + when(config.getSslPemFile()).thenReturn(pemFile); + when(config.getSslKeyPassphrase()).thenReturn("non-null"); + String[] expected = { "mongod", "--quiet", "--fork", "--auth", + "--nohttpinterface", "--bind_ip", config.getBindIP(), + "--dbpath", config.getDBPath().getCanonicalPath(), "--logpath", + config.getLogFile().getCanonicalPath(), "--pidfilepath", + config.getPidFile().getCanonicalPath(), "--port", + Long.toString(config.getPort()), "--sslOnNormalPorts", + "--sslPEMKeyFile", config.getSslPemFile().getCanonicalPath(), + "--sslPEMKeyPassword", config.getSslKeyPassphrase() + }; + List<String> cmds = runner.getStartupCommand(JOURNAL_MONGODB_VERSION); + String[] actual = cmds.toArray(new String[0]); + verifyEquals(expected, actual); + } + + @Test + public void testCommandArgumentsWithSSLEnabledThrowsInvalidConfigException() throws IOException { + when(config.isSslEnabled()).thenReturn(true); + // PEM file can't be null when SSL == true + when(config.getSslPemFile()).thenReturn(null); + try { + runner.getStartupCommand(JOURNAL_MONGODB_VERSION); + fail("Should have thrown exception!"); + } catch (InvalidConfigurationException e) { + assertEquals("No SSL PEM file specified!", e.getMessage()); + } + // Key password can't be null when SSL == true and keyfile present + File pemFile = new File("/path/to/ssl.pem"); + when(config.getSslPemFile()).thenReturn(pemFile); + when(config.getSslKeyPassphrase()).thenReturn(null); + try { + runner.getStartupCommand(JOURNAL_MONGODB_VERSION); + fail("Should have thrown exception!"); + } catch (InvalidConfigurationException e) { + assertEquals("No SSL key passphrase set!", e.getMessage()); + } + } + + private void verifyEquals(String[] expected, String[] actual) { + assertEquals(expected.length, actual.length); + for (int i=0; i < expected.length; i++) { + assertEquals(expected[i], actual[i]); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/db/StorageCommandTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,293 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.agent.cli.impl.db; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.Properties; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + +import junit.framework.Assert; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.redhat.thermostat.agent.cli.impl.db.MongoProcessRunner; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.cli.SimpleArguments; +import com.redhat.thermostat.common.config.InvalidConfigurationException; +import com.redhat.thermostat.common.tools.ApplicationException; +import com.redhat.thermostat.common.tools.ApplicationState; + +public class StorageCommandTest { + + private static final String PORT = "27518"; + private static final String BIND = "127.0.0.1"; + private static final String DB = "storage/db"; + + private String tmpDir; + + @Before + public void setup() { + // need to create a dummy config file for the test + try { + Random random = new Random(); + + tmpDir = System.getProperty("java.io.tmpdir") + File.separatorChar + + Math.abs(random.nextInt()) + File.separatorChar; + + System.setProperty("THERMOSTAT_HOME", tmpDir); + File base = new File(tmpDir + "storage"); + base.mkdirs(); + + File tmpConfigs = new File(base, "db.properties"); + + new File(base, "run").mkdirs(); + new File(base, "logs").mkdirs(); + new File(base, "db").mkdirs(); + + Properties props = new Properties(); + + props.setProperty(DBConfig.BIND.name(), BIND); + props.setProperty(DBConfig.PORT.name(), PORT); + + props.store(new FileOutputStream(tmpConfigs), "thermostat test properties"); + + } catch (IOException e) { + Assert.fail("cannot setup tests: " + e); + } + } + + @Test + public void testConfig() throws CommandException { + SimpleArguments args = new SimpleArguments(); + args.addArgument("quiet", null); + args.addArgument("start", null); + args.addArgument("dryRun", null); + CommandContext ctx = mock(CommandContext.class); + when(ctx.getArguments()).thenReturn(args); + + StorageCommand service = new StorageCommand() { + @Override + MongoProcessRunner createRunner() { + throw new AssertionError("dry run should never create an actual runner"); + } + }; + + service.run(ctx); + + DBStartupConfiguration conf = service.getConfiguration(); + + Assert.assertEquals(tmpDir + DB, conf.getDBPath().getPath()); + Assert.assertEquals(Integer.parseInt(PORT), conf.getPort()); + Assert.assertEquals("mongodb://" + BIND + ":" + PORT , conf.getDBConnectionString()); + } + + private StorageCommand prepareService(boolean startSuccess) throws IOException, + InterruptedException, InvalidConfigurationException, ApplicationException + { + final MongoProcessRunner runner = mock(MongoProcessRunner.class); + if (!startSuccess) { + doThrow(new ApplicationException("mock exception")).when(runner).startService(); + } + + // TODO: stop not tested yet, but be sure it's not called from the code + doThrow(new ApplicationException("mock exception")).when(runner).stopService(); + + StorageCommand service = new StorageCommand() { + @Override + MongoProcessRunner createRunner() { + return runner; + } + }; + + return service; + } + + @Test + public void testListeners() throws InterruptedException, IOException, ApplicationException, InvalidConfigurationException, CommandException + { + StorageCommand service = prepareService(true); + + final CountDownLatch latch = new CountDownLatch(2); + + final boolean[] result = new boolean[2]; + service.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @SuppressWarnings("incomplete-switch") + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = false; + latch.countDown(); + latch.countDown(); + break; + + case SUCCESS: + result[0] = true; + latch.countDown(); + break; + + case START: + result[1] = true; + latch.countDown(); + break; + } + } + }); + + service.run(prepareContext()); + latch.await(); + + Assert.assertTrue(result[0]); + Assert.assertTrue(result[1]); + } + + @Test + public void testListenersFail() throws InterruptedException, IOException, ApplicationException, CommandException, InvalidConfigurationException + { + StorageCommand service = prepareService(false); + + final CountDownLatch latch = new CountDownLatch(1); + final boolean[] result = new boolean[1]; + service.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @SuppressWarnings("incomplete-switch") + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = true; + break; + + case SUCCESS: + result[0] = false; + break; + } + latch.countDown(); + } + }); + + service.run(prepareContext()); + latch.await(); + + Assert.assertTrue(result[0]); + } + + private CommandContext prepareContext() { + SimpleArguments args = new SimpleArguments(); + args.addArgument("quiet", "--quiet"); + args.addArgument("start", "--start"); + CommandContext ctx = mock(CommandContext.class); + when(ctx.getArguments()).thenReturn(args); + return ctx; + } + + @Test + public void testName() { + StorageCommand dbService = new StorageCommand(); + String name = dbService.getName(); + assertEquals("storage", name); + } + + @Test + public void testDescAndUsage() { + StorageCommand dbService = new StorageCommand(); + assertNotNull(dbService.getDescription()); + assertNotNull(dbService.getUsage()); + } + + @Ignore + @Test + public void testOptions() { + StorageCommand dbService = new StorageCommand(); + Options options = dbService.getOptions(); + assertNotNull(options); + assertEquals(4, options.getOptions().size()); + + assertTrue(options.hasOption("dryRun")); + Option dry = options.getOption("dryRun"); + assertEquals("d", dry.getOpt()); + assertEquals("run the service in dry run mode", dry.getDescription()); + assertFalse(dry.isRequired()); + assertFalse(dry.hasArg()); + + assertTrue(options.hasOption("start")); + Option start = options.getOption("start"); + assertEquals("start the database", start.getDescription()); + assertFalse(start.isRequired()); + assertFalse(start.hasArg()); + + assertTrue(options.hasOption("stop")); + Option stop = options.getOption("stop"); + assertEquals("stop the database", stop.getDescription()); + assertFalse(stop.isRequired()); + assertFalse(stop.hasArg()); + + assertTrue(options.hasOption("quiet")); + Option quiet = options.getOption("quiet"); + assertEquals("q", quiet.getOpt()); + assertEquals("don't produce any output", quiet.getDescription()); + assertFalse(quiet.isRequired()); + assertFalse(quiet.hasArg()); + + OptionGroup startStop = options.getOptionGroup(start); + assertTrue(startStop.isRequired()); + @SuppressWarnings("unchecked") + Collection<Option> groupOpts = startStop.getOptions(); + assertEquals(2, groupOpts.size()); + assertTrue(groupOpts.contains(start)); + assertTrue(groupOpts.contains(stop)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/resources/brokenDbConfig.properties Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,2 @@ +PORT=27518 +# missing BIND \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/resources/brokenDbConfig2.properties Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,2 @@ +#PORT=27518 +BIND=127.0.0.1 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/resources/testDbConfig.properties Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,7 @@ +PORT=27518 +BIND=127.0.0.1 + +## SSL config fluff +SSL_ENABLE=true +SSL_PEM_FILE=/path/to/some/pem/file.pem +SSL_KEY_PASSWORD=somepassword \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/resources/testDbConfig2.properties Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,7 @@ +PORT=27518 +BIND=127.0.0.1 + +## SSL config fluff +#SSL_ENABLE=true +#SSL_PEM_FILE=/path/to/some/pem/file.pem +#SSL_KEY_PASSWORD=somepassword \ No newline at end of file
--- a/bundles/pom.xml Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - - Copyright 2012 Red Hat, Inc. - - This file is part of Thermostat. - - Thermostat is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your - option) any later version. - - Thermostat is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thermostat; see the file COPYING. If not see - <http://www.gnu.org/licenses />. - - Linking this code with other modules is making a combined work - based on this code. Thus, the terms and conditions of the GNU - General Public License cover the whole combination. - - As a special exception, the copyright holders of this code give - you permission to link this code with independent modules to - produce an executable, regardless of the license terms of these - independent modules, and to copy and distribute the resulting - executable under terms of your choice, provided that you also - meet, for each linked independent module, the terms and conditions - of the license of that module. An independent module is a module - which is not derived from or based on this code. If you modify - this code, you may extend this exception to your version of the - library, but you are not obligated to do so. If you do not wish - to do so, delete this exception statement from your version. - ---> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat</artifactId> - <version>0.5.0-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-bundles</artifactId> - <packaging>bundle</packaging> - - <name>Service providing entry point to OSGi-land</name> - - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.powermock</groupId> - <artifactId>powermock-api-mockito</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.powermock</groupId> - <artifactId>powermock-module-junit4</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.jboss.netty</groupId> - <artifactId>netty</artifactId> - </dependency> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - <scope>provided</scope> - </dependency> - - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-core</artifactId> - <version>${project.version}</version> - <type>jar</type> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-Activator>com.redhat.thermostat.bundles.impl.Activator</Bundle-Activator> - <Bundle-SymbolicName>com.redhat.thermostat.bundles.core</Bundle-SymbolicName> - <Export-Package> - com.redhat.thermostat.bundles - </Export-Package> - <Private-Package> - com.redhat.thermostat.bundles.impl - </Private-Package> - <!-- Do not autogenerate uses clauses in Manifests --> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - </plugins> - </build> -</project>
--- a/bundles/src/main/java/com/redhat/thermostat/bundles/OSGiRegistry.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.bundles; - -import java.io.IOException; -import java.util.List; - -import org.osgi.framework.BundleException; -import org.osgi.framework.launch.Framework; - -import com.redhat.thermostat.bundles.impl.BundleLoader; -import com.redhat.thermostat.common.Configuration; -import com.redhat.thermostat.common.cli.CommandInfoNotFoundException; -import com.redhat.thermostat.common.cli.CommandInfoSource; - -/** - * A Service that provides features to load bundles for given command names. - */ -public abstract class OSGiRegistry { - - public abstract void setPrintOSGiInfo(boolean printOSGiInfo); - - public abstract void setCommandInfoSource(CommandInfoSource source); - - public abstract void addBundlesFor(String commandName) throws BundleException, CommandInfoNotFoundException, IOException; - - public static void preLoadBundles(Framework framework, List<String> bundleLocations, - boolean printOSGiInfo) throws BundleException { - BundleLoader loader = new BundleLoader(printOSGiInfo); - loader.installAndStartBundles(framework, bundleLocations); - } - - public abstract Configuration getConfiguration(); - -}
--- a/bundles/src/main/java/com/redhat/thermostat/bundles/impl/Activator.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.bundles.impl; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -import com.redhat.thermostat.bundles.OSGiRegistry; -import com.redhat.thermostat.common.Configuration; - -public class Activator implements BundleActivator { - - ServiceRegistration reg; - - @Override - public void start(BundleContext context) throws Exception { - OSGiRegistryImpl bundleRegistry = new OSGiRegistryImpl(new Configuration()); - reg = context.registerService(OSGiRegistry.class.getName(), bundleRegistry, null); - } - - @Override - public void stop(BundleContext context) throws Exception { - if (reg != null) { - reg.unregister(); - reg = null; - } - } - -}
--- a/bundles/src/main/java/com/redhat/thermostat/bundles/impl/BundleLoader.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.bundles.impl; - -import java.util.ArrayList; -import java.util.List; - -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; -import org.osgi.framework.launch.Framework; - -public class BundleLoader { - - private boolean printOSGiInfo = false; - - BundleLoader() { - this(false); - } - - public BundleLoader(boolean printOSGiInfo) { - setPrintOSGiInfo(printOSGiInfo); - } - - public void setPrintOSGiInfo(boolean printOSGiInfo) { - this.printOSGiInfo = printOSGiInfo; - } - - public List<Bundle> installAndStartBundles(Framework framework, - List<String>bundleLocations) throws BundleException { - List<Bundle> bundles = new ArrayList<>(); - BundleContext ctx = framework.getBundleContext(); - for (String location : bundleLocations) { - Bundle bundle = ctx.installBundle(location); - if (printOSGiInfo) { - System.out.println("BundleLoader: installed bundle: \"" + - location + "\" as id " + bundle.getBundleId()); - } - bundles.add(bundle); - } - startBundles(bundles); - return bundles; - } - - private void startBundles(List<Bundle> bundles) throws BundleException { - for (Bundle bundle : bundles) { - - if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) { - if (printOSGiInfo) { - System.out.println("BundleLoader: bundle \"" + bundle.getBundleId() + "\" is a fragment; not starting it"); - } - continue; - } - - if (printOSGiInfo) { - System.out.println("BundleLoader: starting bundle: \"" + bundle.getBundleId() + "\""); - } - // We don't want for the framework to set the auto-start bit. Thus, passing - // START_TRANSIENT explicitly - bundle.start(Bundle.START_TRANSIENT); - } - } - -}
--- a/bundles/src/main/java/com/redhat/thermostat/bundles/impl/OSGiRegistryImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.bundles.impl; - -import com.redhat.thermostat.bundles.OSGiRegistry; -import com.redhat.thermostat.common.Configuration; -import com.redhat.thermostat.common.ConfigurationException; -import com.redhat.thermostat.common.cli.CommandInfoNotFoundException; -import com.redhat.thermostat.common.cli.CommandInfoSource; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleException; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.launch.Framework; - -public class OSGiRegistryImpl extends OSGiRegistry { - - private CommandInfoSource commandInfos; - private Map<String, Bundle> loaded; - private Configuration configuration; - private BundleLoader loader; - - OSGiRegistryImpl(Configuration configuration) throws ConfigurationException, FileNotFoundException, IOException { - initLoadedBundles(); - this.configuration = configuration; - loader = new BundleLoader(configuration.getPrintOSGiInfo()); - } - - private void initLoadedBundles() { - loaded = new HashMap<>(); - Framework framework = getFramework(this.getClass()); - for (Bundle bundle: framework.getBundleContext().getBundles()) { - loaded.put(bundle.getLocation(), bundle); - } - } - - @Override - public void setPrintOSGiInfo(boolean printOSGiInfo) { - configuration.setPrintOSGiInfo(printOSGiInfo); - loader.setPrintOSGiInfo(printOSGiInfo); - } - - @Override - public void setCommandInfoSource(CommandInfoSource source) { - this.commandInfos = source; - } - - @Override - public void addBundlesFor(String commandName) throws BundleException, IOException, CommandInfoNotFoundException { - if (configuration.getPrintOSGiInfo()) { - System.out.println("Loading additional bundles for: " + commandName); - } - List<String> requiredBundles = commandInfos.getCommandInfo(commandName).getDependencyResourceNames(); - List<String> bundlesToLoad = new ArrayList<>(); - if (requiredBundles != null) { - for (String resource : requiredBundles) { - if (!isBundleActive(resource)) { - bundlesToLoad.add(resource); - } - } - } - Framework framework = getFramework(this.getClass()); - List<Bundle> successBundles = loader.installAndStartBundles(framework, bundlesToLoad); - for (Bundle bundle : successBundles) { - loaded.put(bundle.getLocation(), bundle); - } - } - - private boolean isBundleActive(String location) { - Bundle bundle = loaded.get(location); - return (bundle != null) && (bundle.getState() == Bundle.ACTIVE); - } - - private Framework getFramework(Class<?> cls) { - return (Framework) FrameworkUtil.getBundle(cls).getBundleContext().getBundle(0); - } - - @Override - public Configuration getConfiguration() { - return configuration; - } -}
--- a/bundles/src/test/java/com/redhat/thermostat/bundles/OSGiRegistryTest.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.bundles; - -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.powermock.api.mockito.PowerMockito.whenNew; - -import java.util.ArrayList; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.osgi.framework.launch.Framework; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.redhat.thermostat.bundles.impl.BundleLoader; - -@RunWith(PowerMockRunner.class) -@PrepareForTest(OSGiRegistry.class) -public class OSGiRegistryTest { - - @Test - public void testPreLoadBundles() throws Exception { - Framework framework = mock(Framework.class); - ArrayList<String> bundleLocations = new ArrayList<>(); - BundleLoader loader = mock(BundleLoader.class); - whenNew(BundleLoader.class).withParameterTypes(Boolean.TYPE). - withArguments(any()).thenReturn(loader); - - OSGiRegistry.preLoadBundles(framework, bundleLocations, true); - verify(loader).installAndStartBundles(framework, bundleLocations); - } -}
--- a/bundles/src/test/java/com/redhat/thermostat/bundles/impl/BundleLoaderTest.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.bundles.impl; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.Dictionary; -import java.util.Hashtable; -import java.util.List; - -import org.junit.Test; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; -import org.osgi.framework.launch.Framework; - -import com.redhat.thermostat.test.Bug; - -public class BundleLoaderTest { - - @Test - public void verifyBundlesAreInstalledAndStarted() throws BundleException { - final String BUNDLE_LOCATION = "bundle-location-1"; - - Bundle bundle = mock(Bundle.class); - when(bundle.getHeaders()).thenReturn(new Hashtable<>()); - BundleContext bundleContext = mock(BundleContext.class); - when(bundleContext.installBundle(BUNDLE_LOCATION)).thenReturn(bundle); - Framework framework = mock(Framework.class); - when(framework.getBundleContext()).thenReturn(bundleContext); - List<String> bundleLocations = Arrays.asList(BUNDLE_LOCATION); - - BundleLoader loader = new BundleLoader(); - loader.installAndStartBundles(framework, bundleLocations); - - verify(bundle).start(Bundle.START_TRANSIENT); - } - - @Bug(id="1227", - summary="Make sure launcher does not start fragments", - url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1227") - @Test - public void verifyFragmentsAreInstalledButNotStarted() throws BundleException { - final String BUNDLE_LOCATION = "bundle-location-1"; - - Bundle bundle = mock(Bundle.class); - Dictionary<String, String> bundleHeaders = new Hashtable<>(); - bundleHeaders.put(Constants.FRAGMENT_HOST, "foo-bar"); - when(bundle.getHeaders()).thenReturn(bundleHeaders); - - BundleContext bundleContext = mock(BundleContext.class); - when(bundleContext.installBundle(BUNDLE_LOCATION)).thenReturn(bundle); - Framework framework = mock(Framework.class); - when(framework.getBundleContext()).thenReturn(bundleContext); - List<String> bundleLocations = Arrays.asList(BUNDLE_LOCATION); - - BundleLoader loader = new BundleLoader(); - loader.installAndStartBundles(framework, bundleLocations); - - verify(bundle, times(0)).start(Bundle.START_TRANSIENT); - - } -}
--- a/bundles/src/test/java/com/redhat/thermostat/bundles/impl/OSGiRegistryImplTest.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.bundles.impl; - -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.verify; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.whenNew; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.launch.Framework; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.redhat.thermostat.common.Configuration; -import com.redhat.thermostat.common.cli.CommandInfo; -import com.redhat.thermostat.common.cli.CommandInfoSource; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({OSGiRegistryImpl.class, FrameworkUtil.class}) -public class OSGiRegistryImplTest { - - private static final String cmdName = "one"; - - private static final String jar1Name = "/one.jar"; - private static final String jar2Name = "/two.jar"; - private static final String jar3Name = "/three.jar"; - - private Bundle b1, b2, b3; - private List<String> bundleLocs; - - private BundleLoader loader; - private Configuration conf; - - @Before - public void setUp() throws Exception { - conf = mock(Configuration.class); - when(conf.getThermostatHome()).thenReturn("no_matter"); - bundleLocs = Arrays.asList(jar1Name, jar2Name, jar3Name); - b1 = mock(Bundle.class); - when(b1.getLocation()).thenReturn(jar1Name); - when(b1.getState()).thenReturn(Bundle.ACTIVE); - b2 = mock(Bundle.class); - when(b2.getLocation()).thenReturn(jar2Name); - when(b2.getState()).thenReturn(Bundle.ACTIVE); - b3 = mock(Bundle.class); - when(b3.getLocation()).thenReturn(jar3Name); - when(b3.getState()).thenReturn(Bundle.ACTIVE); - List<Bundle> installed = Arrays.asList(b1, b2, b3); - - loader = mock(BundleLoader.class); - when(loader.installAndStartBundles(any(Framework.class), eq(bundleLocs))). - thenReturn(installed); - whenNew(BundleLoader.class).withParameterTypes(Boolean.TYPE). - withArguments(any()).thenReturn(loader); - } - - @Test - public void testLoadBundlesFor() throws Exception { - verifyBundlesLoaded(new Bundle[] {}, bundleLocs); - } - - @Test - public void verifyAlreadyLoadedBundlesNotReloaded() throws Exception { - verifyBundlesLoaded(new Bundle[] {b1, b2}, Arrays.asList(jar3Name)); - } - - private void verifyBundlesLoaded(Bundle[] preloaded, List<String> locationsNeeded) throws Exception { - Bundle theBundle = b2; - BundleContext theContext = mock(BundleContext.class); - when(theContext.getBundles()).thenReturn(preloaded); - Framework theFramework = mock(Framework.class); - when(theFramework.getBundleContext()).thenReturn(theContext); - when(theContext.getBundle(0)).thenReturn(theFramework); - when(theBundle.getBundleContext()).thenReturn(theContext); - mockStatic(FrameworkUtil.class); - when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle); - - OSGiRegistryImpl registry = new OSGiRegistryImpl(conf); - CommandInfoSource infos = mock(CommandInfoSource.class); - CommandInfo info = mock(CommandInfo.class); - when (info.getDependencyResourceNames()).thenReturn(bundleLocs); - when (infos.getCommandInfo(cmdName)).thenReturn(info); - registry.setCommandInfoSource(infos); - registry.addBundlesFor(cmdName); - verify(loader).installAndStartBundles(any(Framework.class), eq(locationsNeeded)); - } - - @Test - public void verifySetOSGiVerbosityByReflection() throws Exception { - - // All this fluff is just so constructor doesn't NPE. - Bundle theBundle = b2; - BundleContext theContext = mock(BundleContext.class); - when(theContext.getBundles()).thenReturn(new Bundle[]{}); - Framework theFramework = mock(Framework.class); - when(theFramework.getBundleContext()).thenReturn(theContext); - when(theContext.getBundle(0)).thenReturn(theFramework); - when(theBundle.getBundleContext()).thenReturn(theContext); - mockStatic(FrameworkUtil.class); - when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle); - - Object registry = new OSGiRegistryImpl(conf); - Class clazz = registry.getClass(); - Method m = clazz.getMethod("setPrintOSGiInfo", Boolean.TYPE); - m.invoke(registry, true); // If this fails, then API has changed in ways that break FrameworkProvider. - } - -}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -49,7 +49,7 @@ static final Key<Boolean> ALIVE_KEY = new Key<>("alive", false); static final Key<String> CONFIG_LISTEN_ADDRESS = new Key<>("configListenAddress", false); - static final Category CATEGORY = new Category("agent-config", + static final Category<AgentInformation> CATEGORY = new Category<>("agent-config", AgentInformation.class, Key.AGENT_ID, START_TIME_KEY, STOP_TIME_KEY,
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/AgentInfoDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,6 +41,7 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Remove; import com.redhat.thermostat.storage.core.Storage; @@ -64,8 +65,8 @@ @Override public List<AgentInformation> getAllAgentInformation() { - Query query = storage.createQuery().from(CATEGORY); - Cursor<AgentInformation> agentCursor = storage.findAllPojos(query, AgentInformation.class); + Query<AgentInformation> query = storage.createQuery(CATEGORY); + Cursor<AgentInformation> agentCursor = query.execute(); List<AgentInformation> results = new ArrayList<>(); @@ -78,11 +79,10 @@ @Override public List<AgentInformation> getAliveAgents() { - Query query = storage.createQuery() - .from(CATEGORY) - .where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true); + Query<AgentInformation> query = storage.createQuery(CATEGORY); + query.where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true); - Cursor<AgentInformation> agentCursor = storage.findAllPojos(query, AgentInformation.class); + Cursor<AgentInformation> agentCursor = query.execute(); List<AgentInformation> results = new ArrayList<>(); @@ -95,16 +95,17 @@ @Override public AgentInformation getAgentInformation(HostRef agentRef) { - Query query = storage.createQuery() - .from(CATEGORY) - .where(Key.AGENT_ID, Criteria.EQUALS, agentRef.getAgentId()); - - return storage.findPojo(query, AgentInformation.class); + Query<AgentInformation> query = storage.createQuery(CATEGORY); + query.where(Key.AGENT_ID, Criteria.EQUALS, agentRef.getAgentId()); + query.limit(1); + return query.execute().next(); } @Override public void addAgentInformation(AgentInformation agentInfo) { - storage.putPojo(AgentInfoDAO.CATEGORY, true, agentInfo); + Put replace = storage.createReplace(CATEGORY); + replace.setPojo(agentInfo); + replace.apply(); } @Override @@ -115,12 +116,13 @@ @Override public void updateAgentInformation(AgentInformation agentInfo) { - Update update = storage.createUpdate().from(CATEGORY).where(Key.AGENT_ID, agentInfo.getAgentId()) - .set(START_TIME_KEY, agentInfo.getStartTime()) - .set(STOP_TIME_KEY, agentInfo.getStopTime()) - .set(ALIVE_KEY, agentInfo.isAlive()) - .set(CONFIG_LISTEN_ADDRESS, agentInfo.getConfigListenAddress()); - storage.updatePojo(update); + Update update = storage.createUpdate(CATEGORY); + update.where(Key.AGENT_ID, agentInfo.getAgentId()); + update.set(START_TIME_KEY, agentInfo.getStartTime()); + update.set(STOP_TIME_KEY, agentInfo.getStopTime()); + update.set(ALIVE_KEY, agentInfo.isAlive()); + update.set(CONFIG_LISTEN_ADDRESS, agentInfo.getConfigListenAddress()); + update.apply(); } }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -51,7 +51,7 @@ static final Key<List<Integer>> PIDS_TO_MONITOR = new Key<>("pids", false); static final Key<Integer> ORDER_VALUE = new Key<>("orderValue", false); - static final Category CATEGORY = new Category("backend-info", + static final Category<BackendInformation> CATEGORY = new Category<>("backend-info", BackendInformation.class, Key.AGENT_ID, BACKEND_NAME, BACKEND_DESCRIPTION,
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -43,6 +43,7 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Remove; @@ -61,12 +62,11 @@ @Override public List<BackendInformation> getBackendInformation(HostRef host) { // Sort by order value - Query query = storage.createQuery() - .from(CATEGORY) - .where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId()); + Query<BackendInformation> query = storage.createQuery(CATEGORY); + query.where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId()); List<BackendInformation> results = new ArrayList<>(); - Cursor<BackendInformation> cursor = storage.findAllPojos(query, BackendInformation.class); + Cursor<BackendInformation> cursor = query.execute(); while (cursor.hasNext()) { BackendInformation backendInfo = cursor.next(); results.add(backendInfo); @@ -93,7 +93,9 @@ @Override public void addBackendInformation(BackendInformation info) { - storage.putPojo(BackendInfoDAO.CATEGORY, false, info); + Put add = storage.createAdd(BackendInfoDAO.CATEGORY); + add.setPojo(info); + add.apply(); } @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -51,7 +51,7 @@ static Key<String> cpuModelKey = new Key<>("cpuModel", false); static Key<Long> hostMemoryTotalKey = new Key<>("totalMemory", false); - static final Category hostInfoCategory = new Category("host-info", + static final Category<HostInfo> hostInfoCategory = new Category<>("host-info", HostInfo.class, Key.AGENT_ID, hostNameKey, osNameKey, osKernelKey, cpuCountKey, cpuModelKey, hostMemoryTotalKey);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostInfoDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,6 +42,7 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Query.Criteria; @@ -62,21 +63,23 @@ @Override public HostInfo getHostInfo(HostRef ref) { - Query query = storage.createQuery() - .from(hostInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId()); - HostInfo result = storage.findPojo(query, HostInfo.class); + Query<HostInfo> query = storage.createQuery(hostInfoCategory); + query.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId()); + query.limit(1); + HostInfo result = query.execute().next(); return result; } @Override public void putHostInfo(HostInfo info) { - storage.putPojo(hostInfoCategory, false, info); + Put add = storage.createAdd(hostInfoCategory); + add.setPojo(info); + add.apply(); } @Override public Collection<HostRef> getHosts() { - Query allHosts = storage.createQuery().from(hostInfoCategory); + Query<HostInfo> allHosts = storage.createQuery(hostInfoCategory); return getHosts(allHosts); } @@ -85,10 +88,8 @@ List<HostRef> hosts = new ArrayList<>(); List<AgentInformation> agentInfos = agentInfoDao.getAliveAgents(); for (AgentInformation agentInfo : agentInfos) { - Query filter = storage.createQuery() - .from(hostInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, agentInfo.getAgentId()); - + Query<HostInfo> filter = storage.createQuery(hostInfoCategory); + filter.where(Key.AGENT_ID, Criteria.EQUALS, agentInfo.getAgentId()); hosts.addAll(getHosts(filter)); } @@ -96,10 +97,10 @@ } - private Collection<HostRef> getHosts(Query filter) { + private Collection<HostRef> getHosts(Query<HostInfo> filter) { Collection<HostRef> hosts = new ArrayList<HostRef>(); - Cursor<HostInfo> hostsCursor = storage.findAllPojos(filter, HostInfo.class); + Cursor<HostInfo> hostsCursor = filter.execute(); while(hostsCursor.hasNext()) { HostInfo host = hostsCursor.next(); String agentId = host.getAgentId();
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java Mon Jan 14 14:04:50 2013 -0500 @@ -50,22 +50,20 @@ public class HostLatestPojoListGetter<T extends TimeStampedPojo> { private final Storage storage; - private final Category cat; - private final Class<T> resultClass; + private final Category<T> cat; - public HostLatestPojoListGetter(Storage storage, Category cat, Class<T> resultClass) { + public HostLatestPojoListGetter(Storage storage, Category<T> cat) { this.storage = storage; this.cat = cat; - this.resultClass = resultClass; } public List<T> getLatest(HostRef hostRef, long since) { - Query query = buildQuery(hostRef, since); + Query<T> query = buildQuery(hostRef, since); return getLatest(query); } - private List<T> getLatest(Query query) { - Cursor<T> cursor = storage.findAllPojos(query, resultClass); + private List<T> getLatest(Query<T> query) { + Cursor<T> cursor = query.execute(); List<T> result = new ArrayList<>(); while (cursor.hasNext()) { T pojo = cursor.next(); @@ -74,13 +72,11 @@ return result; } - protected Query buildQuery(HostRef hostRef, long since) { - Query query = storage.createQuery() - .from(cat) - .where(Key.AGENT_ID, Criteria.EQUALS, hostRef.getAgentId()) - .where(Key.TIMESTAMP, Criteria.GREATER_THAN, since) - .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); - + protected Query<T> buildQuery(HostRef hostRef, long since) { + Query<T> query = storage.createQuery(cat); + query.where(Key.AGENT_ID, Criteria.EQUALS, hostRef.getAgentId()); + query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since); + query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); return query; } }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -48,7 +48,7 @@ static Key<String> ip4AddrKey = new Key<>("ip4Addr", false); static Key<String> ip6AddrKey = new Key<>("ip6Addr", false); - static final Category networkInfoCategory = new Category("network-info", + static final Category<NetworkInterfaceInfo> networkInfoCategory = new Category<>("network-info", NetworkInterfaceInfo.class, Key.AGENT_ID, ifaceKey, ip4AddrKey, ip6AddrKey); public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,9 +41,10 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; class NetworkInterfaceInfoDAOImpl implements NetworkInterfaceInfoDAO { @@ -57,11 +58,10 @@ @Override public List<NetworkInterfaceInfo> getNetworkInterfaces(HostRef ref) { - Query allHostNetworkInterfaces = storage.createQuery() - .from(networkInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId()); + Query<NetworkInterfaceInfo> allHostNetworkInterfaces = storage.createQuery(networkInfoCategory); + allHostNetworkInterfaces.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId()); - Cursor<NetworkInterfaceInfo> cursor = storage.findAllPojos(allHostNetworkInterfaces, NetworkInterfaceInfo.class); + Cursor<NetworkInterfaceInfo> cursor = allHostNetworkInterfaces.execute(); List<NetworkInterfaceInfo> result = new ArrayList<>(); while (cursor.hasNext()) { NetworkInterfaceInfo stat = cursor.next(); @@ -72,7 +72,9 @@ @Override public void putNetworkInterfaceInfo(NetworkInterfaceInfo info) { - storage.putPojo(networkInfoCategory, true, info); + Put replace = storage.createReplace(networkInfoCategory); + replace.setPojo(info); + replace.apply(); } }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -61,7 +61,7 @@ static final Key<Long> startTimeKey = new Key<>("startTimeStamp", false); static final Key<Long> stopTimeKey = new Key<>("stopTimeStamp", false); - static final Category vmInfoCategory = new Category("vm-info", + static final Category<VmInfo> vmInfoCategory = new Category<>("vm-info", VmInfo.class, Key.AGENT_ID, Key.VM_ID, vmPidKey, runtimeVersionKey, javaHomeKey, mainClassKey, commandLineKey, vmArgumentsKey, vmNameKey, vmInfoKey, vmVersionKey,
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,10 +42,11 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmInfo; class VmInfoDAOImpl implements VmInfoDAO { @@ -59,11 +60,11 @@ @Override public VmInfo getVmInfo(VmRef ref) { - Query findMatchingVm = storage.createQuery() - .from(vmInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId()) - .where(Key.VM_ID, Criteria.EQUALS, ref.getId()); - VmInfo result = storage.findPojo(findMatchingVm, VmInfo.class); + Query<VmInfo> findMatchingVm = storage.createQuery(vmInfoCategory); + findMatchingVm.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId()); + findMatchingVm.where(Key.VM_ID, Criteria.EQUALS, ref.getId()); + findMatchingVm.limit(1); + VmInfo result = findMatchingVm.execute().next(); if (result == null) { throw new DAOException("Unknown VM: host:" + ref.getAgent().getAgentId() + ";vm:" + ref.getId()); } @@ -73,15 +74,14 @@ @Override public Collection<VmRef> getVMs(HostRef host) { - Query query = buildQuery(host); - Cursor<VmInfo> cursor = storage.findAllPojos(query, VmInfo.class); + Query<VmInfo> query = buildQuery(host); + Cursor<VmInfo> cursor = query.execute(); return buildVMsFromQuery(cursor, host); } - private Query buildQuery(HostRef host) { - Query query = storage.createQuery() - .from(vmInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId()); + private Query<VmInfo> buildQuery(HostRef host) { + Query<VmInfo> query = storage.createQuery(vmInfoCategory); + query.where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId()); return query; } @@ -111,15 +111,17 @@ @Override public void putVmInfo(VmInfo info) { - storage.putPojo(vmInfoCategory, true, info); + Put replace = storage.createReplace(vmInfoCategory); + replace.setPojo(info); + replace.apply(); } @Override public void putVmStoppedTime(int vmId, long timestamp) { - Update update = storage.createUpdate().from(vmInfoCategory) - .where(Key.VM_ID, vmId) - .set(VmInfoDAO.stopTimeKey, timestamp); - storage.updatePojo(update); + Update update = storage.createUpdate(vmInfoCategory); + update.where(Key.VM_ID, vmId); + update.set(VmInfoDAO.stopTimeKey, timestamp); + update.apply(); } }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java Mon Jan 14 14:04:50 2013 -0500 @@ -50,22 +50,20 @@ public class VmLatestPojoListGetter<T extends TimeStampedPojo> { private final Storage storage; - private final Category cat; - private final Class<T> resultClass; + private final Category<T> cat; - public VmLatestPojoListGetter(Storage storage, Category cat, Class<T> resultClass) { + public VmLatestPojoListGetter(Storage storage, Category<T> cat) { this.storage = storage; this.cat = cat; - this.resultClass = resultClass; } public List<T> getLatest(VmRef vmRef, long since) { - Query query = buildQuery(vmRef, since); + Query<T> query = buildQuery(vmRef, since); return getLatest(query); } - private List<T> getLatest(Query query) { - Cursor<T> cursor = storage.findAllPojos(query, resultClass); + private List<T> getLatest(Query<T> query) { + Cursor<T> cursor = query.execute(); List<T> result = new ArrayList<>(); while (cursor.hasNext()) { T pojo = cursor.next(); @@ -74,13 +72,12 @@ return result; } - protected Query buildQuery(VmRef vmRef, long since) { - Query query = storage.createQuery() - .from(cat) - .where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId()) - .where(Key.VM_ID, Criteria.EQUALS, vmRef.getId()) - .where(Key.TIMESTAMP, Criteria.GREATER_THAN, since) - .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + protected Query<T> buildQuery(VmRef vmRef, long since) { + Query<T> query = storage.createQuery(cat); + query.where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId()); + query.where(Key.VM_ID, Criteria.EQUALS, vmRef.getId()); + query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since); + query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); return query; }
--- a/common/core/src/main/java/com/redhat/thermostat/test/MockQuery.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.test; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import com.redhat.thermostat.storage.core.AbstractQuery; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; - -public class MockQuery extends AbstractQuery { - - public static class WhereClause <T> { - public final Key<T> key; - public final Criteria criteria; - public final T value; - - public WhereClause(Key<T> key, Criteria criteria, T value) { - this.key = key; - this.criteria = criteria; - this.value = value; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (!(obj instanceof WhereClause)) { - return false; - } - WhereClause<?> other = (WhereClause<?>) obj; - return Objects.equals(key, other.key) && Objects.equals(criteria, other.criteria) && Objects.equals(value, other.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, criteria, value); - } - } - - private final List<WhereClause<?>> whereClauses = new ArrayList<>(); - private Category category; - - @Override - public MockQuery from(Category category) { - setCategory(category); - return this; - } - - public Category getCategory() { - return category; - } - - public void setCategory(Category category) { - this.category = category; - } - - @Override - public <T> MockQuery where(Key<T> key, Criteria criteria, T value) { - whereClauses.add(new WhereClause<>(key, criteria, value)); - return this; - } - - public List<WhereClause<?>> getWhereClauses() { - return whereClauses; - } - - public int getWhereClausesCount() { - return whereClauses.size(); - } - - public <T> boolean hasWhereClause(Key<T> key, Criteria criteria, T value) { - for (WhereClause<?> whereClause: whereClauses) { - if (whereClause.equals(new WhereClause<T>(key, criteria, value))) { - return true; - } - } - return false; - } - - public boolean hasWhereClauseFor(Key<?> key) { - for (WhereClause<?> where : whereClauses) { - if (where.key.equals(key)) { - return true; - } - } - return false; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (!(obj instanceof MockQuery)) { - return false; - } - MockQuery other = (MockQuery) obj; - return Objects.equals(getCategory(), other.getCategory()) && Objects.equals(whereClauses, other.whereClauses); - } - - @Override - public int hashCode() { - return Objects.hash(getCategory(), whereClauses); - } - - public boolean hasSort(Key<?> key, SortDirection direction) { - - return getSorts().contains(new Sort(key, direction)); - } - -}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/AgentInfoDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -40,7 +40,6 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -56,12 +55,12 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Remove; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.test.MockQuery; public class AgentInfoDAOTest { @@ -119,9 +118,9 @@ when(agentCursor.next()).thenReturn(agent1).thenReturn(null); Storage storage = mock(Storage.class); - when(storage.findAllPojos(any(Query.class), same(AgentInformation.class))).thenReturn(agentCursor); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); + Query query = mock(Query.class); + when(query.execute()).thenReturn(agentCursor); + when(storage.createQuery(any(Category.class))).thenReturn(query); AgentInfoDAOImpl dao = new AgentInfoDAOImpl(storage); List<AgentInformation> allAgentInfo = dao.getAllAgentInformation(); @@ -140,16 +139,18 @@ when(agentCursor.hasNext()).thenReturn(true).thenReturn(false); when(agentCursor.next()).thenReturn(agent1).thenReturn(null); - MockQuery query = new MockQuery(); + Query query = mock(Query.class); Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(query); - when(storage.findAllPojos(query, AgentInformation.class)).thenReturn(agentCursor); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(agentCursor); AgentInfoDAO dao = new AgentInfoDAOImpl(storage); List<AgentInformation> aliveAgents = dao.getAliveAgents(); - assertEquals(AgentInfoDAO.CATEGORY, query.getCategory()); - assertTrue(query.hasWhereClause(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true)); + verify(storage).createQuery(AgentInfoDAO.CATEGORY); + verify(query).where(AgentInfoDAO.ALIVE_KEY, Criteria.EQUALS, true); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(1, aliveAgents.size()); @@ -162,9 +163,14 @@ public void verifyGetAgentInformationWhenStorageCantFindIt() { HostRef agentRef = mock(HostRef.class); - MockQuery query = new MockQuery(); + Query query = mock(Query.class); + Cursor cursor = mock(Cursor.class); + when(cursor.hasNext()).thenReturn(false); + when(cursor.next()).thenReturn(null); + when(query.execute()).thenReturn(cursor); + Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(query); + when(storage.createQuery(any(Category.class))).thenReturn(query); AgentInfoDAO dao = new AgentInfoDAOImpl(storage); @@ -179,16 +185,21 @@ when(agentRef.getAgentId()).thenReturn(agentInfo1.getAgentId()); Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); - when(storage.findPojo(query, AgentInformation.class)).thenReturn(agentInfo1); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + Cursor cursor = mock(Cursor.class); + when(cursor.hasNext()).thenReturn(true).thenReturn(false); + when(cursor.next()).thenReturn(agentInfo1).thenReturn(null); + when(query.execute()).thenReturn(cursor); AgentInfoDAO dao = new AgentInfoDAOImpl(storage); AgentInformation computed = dao.getAgentInformation(agentRef); - assertEquals(AgentInfoDAO.CATEGORY, query.getCategory()); - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, agentInfo1.getAgentId())); - + verify(storage).createQuery(AgentInfoDAO.CATEGORY); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, agentInfo1.getAgentId()); + verify(query).limit(1); + verify(query).execute(); + verifyNoMoreInteractions(query); AgentInformation expected = agentInfo1; assertSame(expected, computed); } @@ -196,32 +207,36 @@ @Test public void verifyAddAgentInformation() { Storage storage = mock(Storage.class); + Replace replace = mock(Replace.class); + when(storage.createReplace(any(Category.class))).thenReturn(replace); + AgentInfoDAO dao = new AgentInfoDAOImpl(storage); dao.addAgentInformation(agentInfo1); - verify(storage).putPojo(AgentInfoDAO.CATEGORY, true, agentInfo1); - + verify(storage).createReplace(AgentInfoDAO.CATEGORY); + verify(replace).setPojo(agentInfo1); + verify(replace).apply(); } @Test public void verifyUpdateAgentInformation() { - Update mockUpdate = QueryTestHelper.createMockUpdate(); + Update mockUpdate = mock(Update.class); Storage storage = mock(Storage.class); - when(storage.createUpdate()).thenReturn(mockUpdate); + when(storage.createUpdate(any(Category.class))).thenReturn(mockUpdate); AgentInfoDAO dao = new AgentInfoDAOImpl(storage); dao.updateAgentInformation(agentInfo1); - verify(mockUpdate).from(AgentInfoDAO.CATEGORY); + verify(storage).createUpdate(AgentInfoDAO.CATEGORY); verify(mockUpdate).where(Key.AGENT_ID, "1234"); verify(mockUpdate).set(AgentInfoDAO.START_TIME_KEY, 100L); verify(mockUpdate).set(AgentInfoDAO.STOP_TIME_KEY, 10L); verify(mockUpdate).set(AgentInfoDAO.CONFIG_LISTEN_ADDRESS, "foobar:666"); verify(mockUpdate).set(AgentInfoDAO.ALIVE_KEY, true); + verify(mockUpdate).apply(); verifyNoMoreInteractions(mockUpdate); - verify(storage).updatePojo(mockUpdate); }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -38,9 +38,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.Arrays; @@ -51,14 +53,15 @@ import org.junit.Test; import org.mockito.InOrder; +import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Remove; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.BackendInformation; -import com.redhat.thermostat.test.MockQuery; public class BackendInfoDAOTest { @@ -109,11 +112,16 @@ @Test public void verifyAddBackendInformation() { Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + BackendInfoDAO dao = new BackendInfoDAOImpl(storage); dao.addBackendInformation(backendInfo1); - verify(storage).putPojo(BackendInfoDAO.CATEGORY, false, backendInfo1); + verify(storage).createAdd(BackendInfoDAO.CATEGORY); + verify(add).setPojo(backendInfo1); + verify(add).apply(); } @Test @@ -127,17 +135,19 @@ when(backendCursor.hasNext()).thenReturn(true).thenReturn(false); when(backendCursor.next()).thenReturn(backend1).thenReturn(null); - MockQuery query = new MockQuery(); + Query query = mock(Query.class); Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(query); - when(storage.findAllPojos(query, BackendInformation.class)).thenReturn(backendCursor); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(backendCursor); BackendInfoDAO dao = new BackendInfoDAOImpl(storage); List<BackendInformation> result = dao.getBackendInformation(agentref); - assertEquals(BackendInfoDAO.CATEGORY, query.getCategory()); - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID)); + verify(storage).createQuery(BackendInfoDAO.CATEGORY); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(Arrays.asList(backendInfo1), result); }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -40,9 +40,8 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -50,9 +49,8 @@ import java.util.Collection; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; +import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; @@ -60,7 +58,7 @@ import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.AgentInformation; import com.redhat.thermostat.storage.model.HostInfo; -import com.redhat.thermostat.test.MockQuery; + public class HostInfoDAOTest { @@ -99,9 +97,13 @@ public void testGetHostInfo() { Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(new MockQuery()); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL); - when(storage.findPojo(any(Query.class), same(HostInfo.class))).thenReturn(info); + Cursor cursor = mock(Cursor.class); + when(cursor.hasNext()).thenReturn(true).thenReturn(false); + when(cursor.next()).thenReturn(info).thenReturn(null); + when(query.execute()).thenReturn(cursor); AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class); HostInfo result = new HostInfoDAOImpl(storage, agentInfoDao).getHostInfo(new HostRef("some uid", HOST_NAME)); @@ -132,13 +134,9 @@ when(cursor.next()).thenReturn(hostConfig); Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); return storage; } @@ -174,13 +172,9 @@ when(cursor.next()).thenReturn(hostConfig1).thenReturn(hostConfig2).thenReturn(hostConfig3); Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); return storage; } @@ -188,13 +182,18 @@ @Test public void testPutHostInfo() { Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + AgentInfoDAO agentInfo = mock(AgentInfoDAO.class); HostInfo info = new HostInfo(HOST_NAME, OS_NAME, OS_KERNEL, CPU_MODEL, CPU_NUM, MEMORY_TOTAL); HostInfoDAO dao = new HostInfoDAOImpl(storage, agentInfo); dao.putHostInfo(info); - verify(storage).putPojo(HostInfoDAO.hostInfoCategory, false, info); + verify(storage).createAdd(HostInfoDAO.hostInfoCategory); + verify(add).setPojo(info); + verify(add).apply(); } @Test @@ -219,7 +218,7 @@ assertEquals(1, hosts.size()); assertTrue(hosts.contains(new HostRef("123", "fluffhost1"))); - verify(storage, times(1)).findAllPojos(any(Query.class), same(HostInfo.class)); + verify(storage).createQuery(HostInfoDAO.hostInfoCategory); } private Pair<Storage, AgentInfoDAO> setupForSingleAliveHost() { @@ -254,13 +253,10 @@ // storage Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor1); + Query query = mock(Query.class); + + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor1); AgentInfoDAO agentDao = mock(AgentInfoDAO.class); when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1)); @@ -282,7 +278,7 @@ assertTrue(hosts.contains(new HostRef("123", "fluffhost1"))); assertTrue(hosts.contains(new HostRef("456", "fluffhost2"))); assertTrue(hosts.contains(new HostRef("678", "fluffhost3"))); - verify(storage, times(3)).findAllPojos(any(Query.class), same(HostInfo.class)); + verify(storage, atLeast(3)).createQuery(HostInfoDAO.hostInfoCategory); } private Pair<Storage, AgentInfoDAO> setupForAliveHost3() { @@ -332,15 +328,9 @@ // storage Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(HostInfo.class))).thenReturn(cursor1). - thenReturn(cursor2). - thenReturn(cursor3); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor1).thenReturn(cursor2).thenReturn(cursor3); AgentInfoDAO agentDao = mock(AgentInfoDAO.class); when(agentDao.getAliveAgents()).thenReturn(Arrays.asList(agentInfo1, agentInfo2, agentInfo3));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -39,8 +39,11 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.List; @@ -52,10 +55,10 @@ import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Query.Criteria; +import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.CpuStat; -import com.redhat.thermostat.test.MockQuery; public class HostLatestPojoListGetterTest { private static final String AGENT_ID = "agentid"; @@ -63,7 +66,7 @@ private static final String CATEGORY_NAME = "hostcategory"; // Make this one static so we don't get IllegalStateException from trying // to make category of same name while running tests in same classloader. - private static final Category cat = new Category(CATEGORY_NAME); + private static final Category<CpuStat> cat = new Category<>(CATEGORY_NAME, CpuStat.class); private static long t1 = 1; private static long t2 = 5; @@ -95,36 +98,38 @@ @Test public void testBuildQuery() { Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); - when (storage.createQuery()).thenReturn(query); + Query query = mock(Query.class); + when (storage.createQuery(any(Category.class))).thenReturn(query); - HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class); - query = (MockQuery) getter.buildQuery(ref, 123); + HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat); + query = getter.buildQuery(ref, 123); assertNotNull(query); - assertEquals(cat, query.getCategory()); - assertEquals(2, query.getWhereClausesCount()); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l)); - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID)); + verify(storage).createQuery(cat); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verifyNoMoreInteractions(query); } @Test public void testBuildQueryPopulatesUpdateTimes() { Storage storage = mock(Storage.class); - MockQuery ignored = new MockQuery(); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(ignored).thenReturn(query); + Query ignored = mock(Query.class); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(ignored).thenReturn(query); - HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class); - ignored = (MockQuery) getter.buildQuery(ref,Long.MIN_VALUE); // Ignore first return value. + HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat); + ignored = getter.buildQuery(ref,Long.MIN_VALUE); // Ignore first return value. - query = (MockQuery) getter.buildQuery(ref, Long.MIN_VALUE); + query = getter.buildQuery(ref, Long.MIN_VALUE); assertNotNull(query); - assertEquals(cat, query.getCategory()); - assertEquals(2, query.getWhereClausesCount()); - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID)); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(storage, times(2)).createQuery(cat); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verifyNoMoreInteractions(query); } @Test @@ -135,16 +140,16 @@ when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null); Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); - when(storage.findAllPojos(query, CpuStat.class)).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); - HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, CpuStat.class); + HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat); List<CpuStat> stats = getter.getLatest(ref, Long.MIN_VALUE); - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID)); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); assertNotNull(stats); assertEquals(2, stats.size());
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -37,10 +37,11 @@ package com.redhat.thermostat.common.dao; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.Collection; @@ -48,11 +49,14 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; -import com.redhat.thermostat.test.MockQuery; public class NetworkInterfaceInfoDAOTest { @@ -86,9 +90,9 @@ when(cursor.next()).thenReturn(niInfo); Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); - when(storage.findAllPojos(query, NetworkInterfaceInfo.class)).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); HostRef hostRef = mock(HostRef.class); when(hostRef.getAgentId()).thenReturn("system"); @@ -96,7 +100,9 @@ NetworkInterfaceInfoDAO dao = new NetworkInterfaceInfoDAOImpl(storage); List<NetworkInterfaceInfo> netInfo = dao.getNetworkInterfaces(hostRef); - assertFalse(query.hasWhereClauseFor(Key.TIMESTAMP)); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system"); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(1, netInfo.size()); @@ -110,12 +116,17 @@ @Test public void testPutNetworkInterfaceInfo() { Storage storage = mock(Storage.class); + Replace replace = mock(Replace.class); + when(storage.createReplace(any(Category.class))).thenReturn(replace); + NetworkInterfaceInfo info = new NetworkInterfaceInfo(INTERFACE_NAME); info.setIp4Addr(IPV4_ADDR); info.setIp6Addr(IPV6_ADDR); NetworkInterfaceInfoDAO dao = new NetworkInterfaceInfoDAOImpl(storage); dao.putNetworkInterfaceInfo(info); - verify(storage).putPojo(NetworkInterfaceInfoDAO.networkInfoCategory, true, info); + verify(storage).createReplace(NetworkInterfaceInfoDAO.networkInfoCategory); + verify(replace).setPojo(info); + verify(replace).apply(); } }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/QueryTestHelper.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/QueryTestHelper.java Mon Jan 14 14:04:50 2013 -0500 @@ -43,23 +43,11 @@ import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Remove; -import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.core.Query.Criteria; public class QueryTestHelper { @SuppressWarnings("unchecked") - public static Update createMockUpdate() { - Update mockUpdate = mock(Update.class); - when(mockUpdate.from(any(Category.class))).thenReturn(mockUpdate); - when(mockUpdate.where(any(Key.class), any())).thenReturn(mockUpdate); - when(mockUpdate.set(any(Key.class), any())).thenReturn(mockUpdate); - return mockUpdate; - } - - @SuppressWarnings("unchecked") public static Remove createMockRemove() { Remove mockRemove = mock(Remove.class); when(mockRemove.from(any(Category.class))).thenReturn(mockRemove); @@ -67,11 +55,4 @@ return mockRemove; } - @SuppressWarnings("unchecked") - public static Query createMockQuery() { - Query mockQuery = mock(Query.class); - when(mockQuery.from(any(Category.class))).thenReturn(mockQuery); - when(mockQuery.where(any(Key.class), any(Criteria.class), any())).thenReturn(mockQuery); - return mockQuery; - } }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -57,11 +57,10 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmInfo; -import com.redhat.thermostat.test.MockQuery; public class VmInfoDAOTest { @@ -125,10 +124,13 @@ public void testGetVmInfo() { Storage storage = mock(Storage.class); - Query query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); VmInfo expected = new VmInfo(vmId, startTime, stopTime, jVersion, jHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, props, env, libs); - when(storage.findPojo(query, VmInfo.class)).thenReturn(expected); + Cursor cursor = mock(Cursor.class); + when(cursor.hasNext()).thenReturn(true).thenReturn(false); + when(cursor.next()).thenReturn(expected).thenReturn(null); + when(query.execute()).thenReturn(cursor); HostRef hostRef = mock(HostRef.class); when(hostRef.getAgentId()).thenReturn("system"); @@ -146,9 +148,11 @@ public void testGetVmInfoUnknownVM() { Storage storage = mock(Storage.class); - Query query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); - + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + Cursor cursor = mock(Cursor.class); + when(query.execute()).thenReturn(cursor); + HostRef hostRef = mock(HostRef.class); when(hostRef.getAgentId()).thenReturn("system"); @@ -178,9 +182,6 @@ } private Storage setupStorageForSingleVM() { - Query expectedQuery = new MockQuery() - .from(VmInfoDAO.vmInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, "123"); VmInfo vm1 = new VmInfo(); vm1.setVmPid(123); @@ -192,8 +193,9 @@ when(singleVMCursor.next()).thenReturn(vm1); Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(new MockQuery()); - when(storage.findAllPojos(expectedQuery, VmInfo.class)).thenReturn(singleVMCursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(singleVMCursor); return storage; } @@ -210,9 +212,6 @@ } private Storage setupStorageForMultiVM() { - Query expectedQuery = new MockQuery() - .from(VmInfoDAO.vmInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, "456"); VmInfo vm1 = new VmInfo(); vm1.setVmPid(123); @@ -228,8 +227,9 @@ when(multiVMsCursor.next()).thenReturn(vm1).thenReturn(vm2); Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(new MockQuery()); - when(storage.findAllPojos(expectedQuery, VmInfo.class)).thenReturn(multiVMsCursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(multiVMsCursor); return storage; } @@ -253,27 +253,33 @@ public void testPutVmInfo() { Storage storage = mock(Storage.class); + Replace replace = mock(Replace.class); + when(storage.createReplace(any(Category.class))).thenReturn(replace); + VmInfo info = new VmInfo(vmId, startTime, stopTime, jVersion, jHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, props, env, libs); VmInfoDAO dao = new VmInfoDAOImpl(storage); dao.putVmInfo(info); - verify(storage).putPojo(VmInfoDAO.vmInfoCategory, true, info); + verify(storage).createReplace(VmInfoDAO.vmInfoCategory); + verify(replace).setPojo(info); + verify(replace).apply(); } @Test public void testPutVmStoppedTime() { - Update mockUpdate = QueryTestHelper.createMockUpdate(); + Update mockUpdate = mock(Update.class); Storage storage = mock(Storage.class); - when(storage.createUpdate()).thenReturn(mockUpdate); + when(storage.createUpdate(any(Category.class))).thenReturn(mockUpdate); + VmInfoDAO dao = new VmInfoDAOImpl(storage); dao.putVmStoppedTime(vmId, stopTime); - verify(mockUpdate).from(VmInfoDAO.vmInfoCategory); + verify(storage).createUpdate(VmInfoDAO.vmInfoCategory); verify(mockUpdate).where(Key.VM_ID, 1); verify(mockUpdate).set(VmInfoDAO.stopTimeKey, 3L); + verify(mockUpdate).apply(); verifyNoMoreInteractions(mockUpdate); - verify(storage).updatePojo(mockUpdate); } }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -38,11 +38,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.List; @@ -54,10 +54,9 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmClassStat; -import com.redhat.thermostat.test.MockQuery; public class VmLatestPojoListGetterTest { private static final String AGENT_ID = "agentid"; @@ -67,7 +66,7 @@ private static final String CATEGORY_NAME = "vmcategory"; // Make this one static so we don't get IllegalStateException from trying // to make category of same name while running tests in same classloader. - private static final Category cat = new Category(CATEGORY_NAME); + private static final Category<VmClassStat> cat = new Category<>(CATEGORY_NAME, VmClassStat.class); private static long t1 = 1; private static long t2 = 5; @@ -93,37 +92,39 @@ @Test public void testBuildQuery() { Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); - VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class); - query = (MockQuery) getter.buildQuery(vmRef, 123l); + VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat); + query = getter.buildQuery(vmRef, 123l); assertNotNull(query); - assertEquals(cat, query.getCategory()); - assertEquals(3, query.getWhereClausesCount()); - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID)); - assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_PID)); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l)); + verify(storage).createQuery(cat); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verifyNoMoreInteractions(query); } @Test public void testBuildQueryPopulatesUpdateTimes() { Storage storage = mock(Storage.class); - MockQuery ignored = new MockQuery(); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(ignored).thenReturn(query); + Query ignored = mock(Query.class); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(ignored).thenReturn(query); - VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class); + VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat); getter.buildQuery(vmRef, Long.MIN_VALUE); // Ignore first return value. - query = (MockQuery) getter.buildQuery(vmRef, Long.MIN_VALUE); + query = getter.buildQuery(vmRef, Long.MIN_VALUE); assertNotNull(query); - assertEquals(cat, query.getCategory()); - assertEquals(3, query.getWhereClausesCount()); - assertTrue(query.hasWhereClauseFor(Key.AGENT_ID)); - assertTrue(query.hasWhereClauseFor(Key.VM_ID)); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(storage, times(2)).createQuery(cat); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verifyNoMoreInteractions(query); } @Test @@ -134,19 +135,21 @@ when(cursor.next()).thenReturn(result1).thenReturn(result2).thenReturn(null); Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); - when(storage.findAllPojos(any(Query.class), same(VmClassStat.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); - VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, VmClassStat.class); + VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat); List<VmClassStat> stats = getter.getLatest(vmRef, t2); - verify(storage).findAllPojos(any(Query.class), same(VmClassStat.class)); - - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID)); - assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_PID)); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, t2)); + verify(storage).createQuery(cat); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_PID); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, t2); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verify(query).execute(); + verifyNoMoreInteractions(query); assertNotNull(stats); assertEquals(2, stats.size());
--- a/distribution/config/db.properties Wed Jan 09 14:59:30 2013 -0500 +++ b/distribution/config/db.properties Mon Jan 14 14:04:50 2013 -0500 @@ -1,2 +1,57 @@ +# Copyright 2012 Red Hat, Inc. +# +# This file is part of Thermostat. +# +# Thermostat is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 2, or (at your +# option) any later version. +# +# Thermostat is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Thermostat; see the file COPYING. If not see +# <http://www.gnu.org/licenses/>. +# +# Linking this code with other modules is making a combined work +# based on this code. Thus, the terms and conditions of the GNU +# General Public License cover the whole combination. +# +# As a special exception, the copyright holders of this code give +# you permission to link this code with independent modules to +# produce an executable, regardless of the license terms of these +# independent modules, and to copy and distribute the resulting +# executable under terms of your choice, provided that you also +# meet, for each linked independent module, the terms and conditions +# of the license of that module. An independent module is a module +# which is not derived from or based on this code. If you modify +# this code, you may extend this exception to your version of the +# library, but you are not obligated to do so. If you do not wish +# to do so, delete this exception statement from your version. + +################################################################### +# Basic storage configuration +################################################################### + PORT=27518 BIND=127.0.0.1 + +################################################################### +# SSL configuration +################################################################### +# Uncomment the following line in order to start storage (currently +# mongodb) with SSL enabled. +#SSL_ENABLE=true +# +# If SSL_ENABLE=true, the path to the PEM encoded private key and +# the server certificate needs to be specified. Uncomment the +# following line and set the path appropriately. +#SSL_PEM_FILE=/path/to/some/pem/file.pem +# +# If SSL_ENABLE=true, the passphrase for the server certificate +# needs to be specified. If the server key was not encrypted any +# non-empty password will work. +#SSL_KEY_PASSWORD=somepassword \ No newline at end of file
--- a/distribution/pom.xml Wed Jan 09 14:59:30 2013 -0500 +++ b/distribution/pom.xml Mon Jan 14 14:04:50 2013 -0500 @@ -322,11 +322,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-bundles</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-launcher</artifactId> <version>${project.version}</version> </dependency>
--- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/CpuStatDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/CpuStatDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -48,7 +48,7 @@ static Key<List<Double>> cpuLoadKey = new Key<>("perProcessorUsage", false); - static final Category cpuStatCategory = new Category("cpu-stats", + static final Category<CpuStat> cpuStatCategory = new Category<>("cpu-stats", CpuStat.class, Key.AGENT_ID, Key.TIMESTAMP, cpuLoadKey); List<CpuStat> getLatestCpuStats(HostRef ref, long since);
--- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,6 +41,7 @@ import com.redhat.thermostat.common.dao.HostLatestPojoListGetter; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.host.cpu.common.CpuStatDAO; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.CpuStat; @@ -53,7 +54,7 @@ CpuStatDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(cpuStatCategory); - this.getter = new HostLatestPojoListGetter<>(storage, cpuStatCategory, CpuStat.class); + this.getter = new HostLatestPojoListGetter<>(storage, cpuStatCategory); } @Override @@ -63,7 +64,9 @@ @Override public void putCpuStat(CpuStat stat) { - storage.putPojo(cpuStatCategory, false, stat); + Put add = storage.createAdd(cpuStatCategory); + add.setPojo(stat); + add.apply(); } @Override
--- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,9 +41,11 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.same; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.Collection; @@ -53,15 +55,14 @@ import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.host.cpu.common.CpuStatDAO; -import com.redhat.thermostat.host.cpu.common.internal.CpuStatDAOImpl; +import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.CpuStat; -import com.redhat.thermostat.test.MockQuery; public class CpuStatDAOTest { @@ -82,7 +83,7 @@ @SuppressWarnings("unchecked") Cursor<CpuStat> cursor = mock(Cursor.class); Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); + Query query = mock(Query.class); HostRef hostRef = mock(HostRef.class); CpuStatDAO dao = new CpuStatDAOImpl(storage); @@ -92,13 +93,17 @@ when(cursor.hasNext()).thenReturn(true).thenReturn(false); when(cursor.next()).thenReturn(cpuStat); - when(storage.createQuery()).thenReturn(query); - when(storage.findAllPojos(query, CpuStat.class)).thenReturn(cursor); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); when(hostRef.getAgentId()).thenReturn("system"); List<CpuStat> cpuStats = dao.getLatestCpuStats(hostRef, Long.MIN_VALUE); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system"); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(1, cpuStats.size()); CpuStat stat = cpuStats.get(0); @@ -113,7 +118,7 @@ @SuppressWarnings("unchecked") Cursor<CpuStat> cursor = mock(Cursor.class); Storage storage = mock(Storage.class); - MockQuery query = new MockQuery(); + Query query = mock(Query.class); HostRef hostRef = mock(HostRef.class); CpuStatDAO dao = new CpuStatDAOImpl(storage); @@ -123,26 +128,31 @@ when(cursor.hasNext()).thenReturn(true).thenReturn(false); when(cursor.next()).thenReturn(cpuStat); - when(storage.createQuery()).thenReturn(query); - when(storage.findAllPojos(any(Query.class), same(CpuStat.class))).thenReturn(cursor); + when(storage.createQuery(CpuStatDAO.cpuStatCategory)).thenReturn(query); + when(query.execute()).thenReturn(cursor); when(hostRef.getAgentId()).thenReturn("system"); dao.getLatestCpuStats(hostRef, Long.MIN_VALUE); dao.getLatestCpuStats(hostRef, Long.MIN_VALUE); - verify(storage, times(2)).findAllPojos(query, CpuStat.class); - - query.hasWhereClauseFor(Key.TIMESTAMP); + verify(query, times(2)).execute(); + verify(query, atLeastOnce()).where(same(Key.AGENT_ID), same(Criteria.EQUALS), any()); + verify(query, atLeastOnce()).where(same(Key.TIMESTAMP), any(Criteria.class), any()); } @Test public void testPutCpuStat() { Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + CpuStat stat = new CpuStat(1, new double[] {5.0, 10.0, 15.0}); CpuStatDAO dao = new CpuStatDAOImpl(storage); dao.putCpuStat(stat); - verify(storage).putPojo(CpuStatDAO.cpuStatCategory, false, stat); + verify(storage).createAdd(CpuStatDAO.cpuStatCategory); + verify(add).setPojo(stat); + verify(add).apply(); } @Test
--- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/MemoryStatDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/MemoryStatDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -54,7 +54,7 @@ static Key<Long> memorySwapFreeKey = new Key<>("swapFree", false); static Key<Long> memoryCommitLimitKey = new Key<>("commitLimit", false); - static final Category memoryStatCategory = new Category("memory-stats", + static final Category<MemoryStat> memoryStatCategory = new Category<>("memory-stats", MemoryStat.class, Key.AGENT_ID, Key.TIMESTAMP, memoryTotalKey, memoryFreeKey, memoryBuffersKey, memoryCachedKey, memorySwapTotalKey, memorySwapFreeKey, memoryCommitLimitKey);
--- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,6 +41,7 @@ import com.redhat.thermostat.common.dao.HostLatestPojoListGetter; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.host.memory.common.MemoryStatDAO; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.MemoryStat; @@ -53,7 +54,7 @@ MemoryStatDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(memoryStatCategory); - this.getter = new HostLatestPojoListGetter<>(storage, memoryStatCategory, MemoryStat.class); + this.getter = new HostLatestPojoListGetter<>(storage, memoryStatCategory); } @Override @@ -63,7 +64,9 @@ @Override public void putMemoryStat(MemoryStat stat) { - storage.putPojo(memoryStatCategory, false, stat); + Put add = storage.createAdd(memoryStatCategory); + add.setPojo(stat); + add.apply(); } @Override
--- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,6 +42,7 @@ import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.Collection; @@ -54,6 +55,7 @@ import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.host.memory.common.MemoryStatDAO; +import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; @@ -61,7 +63,6 @@ import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.MemoryStat; -import com.redhat.thermostat.test.MockQuery; public class MemoryStatDAOTest { @@ -101,13 +102,9 @@ when(cursor.next()).thenReturn(memStat1); Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(MemoryStat.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); HostRef hostRef = mock(HostRef.class); when(hostRef.getAgentId()).thenReturn("system"); @@ -115,9 +112,12 @@ MemoryStatDAO dao = new MemoryStatDAOImpl(storage); List<MemoryStat> memoryStats = dao.getLatestMemoryStats(hostRef, Long.MIN_VALUE); - ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class); - verify(storage).findAllPojos(arg.capture(), same(MemoryStat.class)); - assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(storage).createQuery(MemoryStatDAO.memoryStatCategory); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system"); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(1, memoryStats.size()); MemoryStat stat = memoryStats.get(0); @@ -135,11 +135,16 @@ @Test public void testPutMemoryStat() { Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + MemoryStat stat = new MemoryStat(TIMESTAMP, TOTAL, FREE, BUFFERS, CACHED, SWAP_TOTAL, SWAP_FREE, COMMIT_LIMIT); MemoryStatDAO dao = new MemoryStatDAOImpl(storage); dao.putMemoryStat(stat); - verify(storage).putPojo(MemoryStatDAO.memoryStatCategory, false, stat); + verify(storage).createAdd(MemoryStatDAO.memoryStatCategory); + verify(add).setPojo(stat); + verify(add).apply(); } @Test
--- a/launcher/pom.xml Wed Jan 09 14:59:30 2013 -0500 +++ b/launcher/pom.xml Mon Jan 14 14:04:50 2013 -0500 @@ -110,11 +110,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-bundles</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-common-test</artifactId> <version>${project.version}</version> <scope>test</scope>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/BundleManager.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,69 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher; + +import java.io.IOException; +import java.util.List; + +import org.osgi.framework.BundleException; +import org.osgi.framework.launch.Framework; + +import com.redhat.thermostat.common.Configuration; +import com.redhat.thermostat.common.cli.CommandInfoNotFoundException; +import com.redhat.thermostat.common.cli.CommandInfoSource; +import com.redhat.thermostat.launcher.internal.BundleLoader; + +/** + * A Service that provides features to load bundles for given command names. + */ +public abstract class BundleManager { + + public abstract void setPrintOSGiInfo(boolean printOSGiInfo); + + public abstract void setCommandInfoSource(CommandInfoSource source); + + public abstract void addBundlesFor(String commandName) throws BundleException, CommandInfoNotFoundException, IOException; + + public static void preLoadBundles(Framework framework, List<String> bundleLocations, + boolean printOSGiInfo) throws BundleException { + BundleLoader loader = new BundleLoader(printOSGiInfo); + loader.installAndStartBundles(framework, bundleLocations); + } + + public abstract Configuration getConfiguration(); + +}
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java Wed Jan 09 14:59:30 2013 -0500 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java Mon Jan 14 14:04:50 2013 -0500 @@ -36,70 +36,85 @@ package com.redhat.thermostat.launcher.internal; -import java.util.Map; - import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; -import com.redhat.thermostat.bundles.OSGiRegistry; import com.redhat.thermostat.common.CommandLoadingBundleActivator; -import com.redhat.thermostat.common.MultipleServiceTracker; -import com.redhat.thermostat.common.MultipleServiceTracker.Action; +import com.redhat.thermostat.common.Configuration; import com.redhat.thermostat.common.cli.CommandContextFactory; import com.redhat.thermostat.common.cli.CommandInfoSource; +import com.redhat.thermostat.launcher.BundleManager; import com.redhat.thermostat.launcher.Launcher; import com.redhat.thermostat.utils.keyring.Keyring; public class Activator extends CommandLoadingBundleActivator { + + @SuppressWarnings({"rawtypes", "unchecked"}) + class RegisterLauncherCustomizer implements ServiceTrackerCustomizer { - class RegisterLauncherAction implements Action { - + private ServiceRegistration launcherReg; + private ServiceRegistration bundleManReg; + private ServiceRegistration cmdInfoReg; private BundleContext context; - private ServiceReference registryReference; + private BundleManager bundleService; - RegisterLauncherAction(BundleContext context) { + RegisterLauncherCustomizer(BundleContext context, BundleManager bundleService) { this.context = context; + this.bundleService = bundleService; } @Override - public void dependenciesAvailable(Map<String, Object> services) { - - registryReference = context.getServiceReference(OSGiRegistry.class); - OSGiRegistry bundleService = (OSGiRegistry) context.getService(registryReference); + public Object addingService(ServiceReference reference) { + // keyring is now ready + Keyring keyring = (Keyring)context.getService(reference); + // Register Launcher service since FrameworkProvider is waiting for it blockingly. CommandInfoSourceImpl commands = new CommandInfoSourceImpl(bundleService.getConfiguration().getThermostatHome()); - context.registerService(CommandInfoSource.class, commands, null); + cmdInfoReg = context.registerService(CommandInfoSource.class, commands, null); bundleService.setCommandInfoSource(commands); LauncherImpl launcher = new LauncherImpl(context, new CommandContextFactory(context), bundleService); - launcherServiceRegistration = context.registerService(Launcher.class.getName(), launcher, null); + launcherReg = context.registerService(Launcher.class.getName(), launcher, null); + bundleManReg = context.registerService(BundleManager.class, bundleService, null); + return keyring; } @Override - public void dependenciesUnavailable() { - launcherServiceRegistration.unregister(); - context.ungetService(registryReference); + public void modifiedService(ServiceReference reference, Object service) { + // nothing + } + + @Override + public void removedService(ServiceReference reference, Object service) { + // Keyring is gone, remove launcher, et. al. as well + launcherReg.unregister(); + bundleManReg.unregister(); + cmdInfoReg.unregister(); } } @SuppressWarnings("rawtypes") - private ServiceRegistration launcherServiceRegistration; - private MultipleServiceTracker tracker; + private ServiceTracker serviceTracker; + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void start(final BundleContext context) throws Exception { super.start(context); - - tracker = new MultipleServiceTracker(context, new Class[] {OSGiRegistry.class, Keyring.class}, new RegisterLauncherAction(context)); - tracker.open(); + BundleManager bundleService = new BundleManagerImpl(new Configuration()); + ServiceTrackerCustomizer customizer = new RegisterLauncherCustomizer(context, bundleService); + serviceTracker = new ServiceTracker(context, Keyring.class, customizer); + // Track for Keyring service. + serviceTracker.open(); } @Override public void stop(BundleContext context) throws Exception { super.stop(context); - if (tracker != null) { - tracker.close(); + if (serviceTracker != null) { + serviceTracker.close(); } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BundleLoader.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,99 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.launch.Framework; + +public class BundleLoader { + + private boolean printOSGiInfo = false; + + BundleLoader() { + this(false); + } + + public BundleLoader(boolean printOSGiInfo) { + setPrintOSGiInfo(printOSGiInfo); + } + + public void setPrintOSGiInfo(boolean printOSGiInfo) { + this.printOSGiInfo = printOSGiInfo; + } + + public List<Bundle> installAndStartBundles(Framework framework, + List<String>bundleLocations) throws BundleException { + List<Bundle> bundles = new ArrayList<>(); + BundleContext ctx = framework.getBundleContext(); + for (String location : bundleLocations) { + Bundle bundle = ctx.installBundle(location); + if (printOSGiInfo) { + System.out.println("BundleLoader: installed bundle: \"" + + location + "\" as id " + bundle.getBundleId()); + } + bundles.add(bundle); + } + startBundles(bundles); + return bundles; + } + + private void startBundles(List<Bundle> bundles) throws BundleException { + for (Bundle bundle : bundles) { + + if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) { + if (printOSGiInfo) { + System.out.println("BundleLoader: bundle \"" + bundle.getBundleId() + "\" is a fragment; not starting it"); + } + continue; + } + + if (printOSGiInfo) { + System.out.println("BundleLoader: starting bundle: \"" + bundle.getBundleId() + "\""); + } + // We don't want for the framework to set the auto-start bit. Thus, passing + // START_TRANSIENT explicitly + bundle.start(Bundle.START_TRANSIENT); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BundleManagerImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,123 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher.internal; + +import com.redhat.thermostat.common.Configuration; +import com.redhat.thermostat.common.ConfigurationException; +import com.redhat.thermostat.common.cli.CommandInfoNotFoundException; +import com.redhat.thermostat.common.cli.CommandInfoSource; +import com.redhat.thermostat.launcher.BundleManager; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.launch.Framework; + +public class BundleManagerImpl extends BundleManager { + + private CommandInfoSource commandInfos; + private Map<String, Bundle> loaded; + private Configuration configuration; + private BundleLoader loader; + + BundleManagerImpl(Configuration configuration) throws ConfigurationException, FileNotFoundException, IOException { + initLoadedBundles(); + this.configuration = configuration; + loader = new BundleLoader(configuration.getPrintOSGiInfo()); + } + + private void initLoadedBundles() { + loaded = new HashMap<>(); + Framework framework = getFramework(this.getClass()); + for (Bundle bundle: framework.getBundleContext().getBundles()) { + loaded.put(bundle.getLocation(), bundle); + } + } + + @Override + public void setPrintOSGiInfo(boolean printOSGiInfo) { + configuration.setPrintOSGiInfo(printOSGiInfo); + loader.setPrintOSGiInfo(printOSGiInfo); + } + + @Override + public void setCommandInfoSource(CommandInfoSource source) { + this.commandInfos = source; + } + + @Override + public void addBundlesFor(String commandName) throws BundleException, IOException, CommandInfoNotFoundException { + if (configuration.getPrintOSGiInfo()) { + System.out.println("Loading additional bundles for: " + commandName); + } + List<String> requiredBundles = commandInfos.getCommandInfo(commandName).getDependencyResourceNames(); + List<String> bundlesToLoad = new ArrayList<>(); + if (requiredBundles != null) { + for (String resource : requiredBundles) { + if (!isBundleActive(resource)) { + bundlesToLoad.add(resource); + } + } + } + Framework framework = getFramework(this.getClass()); + List<Bundle> successBundles = loader.installAndStartBundles(framework, bundlesToLoad); + for (Bundle bundle : successBundles) { + loaded.put(bundle.getLocation(), bundle); + } + } + + private boolean isBundleActive(String location) { + Bundle bundle = loaded.get(location); + return (bundle != null) && (bundle.getState() == Bundle.ACTIVE); + } + + private Framework getFramework(Class<?> cls) { + return (Framework) FrameworkUtil.getBundle(cls).getBundleContext().getBundle(0); + } + + @Override + public Configuration getConfiguration() { + return configuration; + } +}
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -50,7 +50,6 @@ import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; -import com.redhat.thermostat.bundles.OSGiRegistry; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ActionNotifier; import com.redhat.thermostat.common.ApplicationService; @@ -72,6 +71,7 @@ import com.redhat.thermostat.common.utils.OSGIUtils; import com.redhat.thermostat.launcher.CommonCommandOptions; import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.launcher.BundleManager; import com.redhat.thermostat.storage.core.ConnectionException; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.StorageException; @@ -89,14 +89,14 @@ private final Semaphore argsBarrier = new Semaphore(0); private BundleContext context; - private OSGiRegistry registry; + private BundleManager registry; private final DbServiceFactory dbServiceFactory; - public LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, OSGiRegistry registry) { + public LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, BundleManager registry) { this(context, cmdCtxFactory, registry, new LoggingInitializer(), new DbServiceFactory()); } - LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, OSGiRegistry registry, + LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, BundleManager registry, LoggingInitializer loggingInitializer, DbServiceFactory dbServiceFactory) { this.context = context; this.cmdCtxFactory = cmdCtxFactory;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/BundleManagerTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,70 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.whenNew; + +import java.util.ArrayList; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osgi.framework.launch.Framework; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.redhat.thermostat.launcher.BundleManager; +import com.redhat.thermostat.launcher.internal.BundleLoader; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(BundleManager.class) +public class BundleManagerTest { + + @Test + public void testPreLoadBundles() throws Exception { + Framework framework = mock(Framework.class); + ArrayList<String> bundleLocations = new ArrayList<>(); + BundleLoader loader = mock(BundleLoader.class); + whenNew(BundleLoader.class).withParameterTypes(Boolean.TYPE). + withArguments(any()).thenReturn(loader); + + BundleManager.preLoadBundles(framework, bundleLocations, true); + verify(loader).installAndStartBundles(framework, bundleLocations); + } +}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -36,6 +36,9 @@ package com.redhat.thermostat.launcher.internal; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; @@ -46,6 +49,9 @@ import static org.powermock.api.mockito.PowerMockito.verifyNew; import static org.powermock.api.mockito.PowerMockito.whenNew; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Dictionary; import java.util.Hashtable; @@ -55,41 +61,55 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.launch.Framework; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; +import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import com.redhat.thermostat.bundles.OSGiRegistry; import com.redhat.thermostat.common.Configuration; import com.redhat.thermostat.common.MultipleServiceTracker; import com.redhat.thermostat.common.MultipleServiceTracker.Action; import com.redhat.thermostat.common.cli.Command; import com.redhat.thermostat.common.cli.CommandInfo; +import com.redhat.thermostat.common.cli.CommandInfoSource; import com.redhat.thermostat.common.utils.ServiceRegistry; import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.launcher.BundleManager; +import com.redhat.thermostat.launcher.internal.Activator.RegisterLauncherCustomizer; +import com.redhat.thermostat.test.StubBundleContext; import com.redhat.thermostat.utils.keyring.Keyring; @RunWith(PowerMockRunner.class) -@PrepareForTest({Activator.class}) +@PrepareForTest({Activator.class, Activator.RegisterLauncherCustomizer.class, FrameworkUtil.class}) public class ActivatorTest { private BundleContext context; private MultipleServiceTracker tracker; private ServiceReference registryServiceReference, helpCommandReference; private ServiceRegistration launcherServiceRegistration, helpCommandRegistration; - private OSGiRegistry registryService; + private BundleManager registryService; private Command helpCommand; @Before public void setUp() throws Exception { + Path tempDir = createStubThermostatHome(); + System.setProperty("THERMOSTAT_HOME", tempDir.toString()); + context = mock(BundleContext.class); + setupOsgiRegistryImplMock(); registryServiceReference = mock(ServiceReference.class); launcherServiceRegistration = mock(ServiceRegistration.class); - registryService = mock(OSGiRegistry.class); - when(context.getServiceReference(eq(OSGiRegistry.class))).thenReturn(registryServiceReference); + registryService = mock(BundleManager.class); + when(context.getServiceReference(eq(BundleManager.class))).thenReturn(registryServiceReference); when(context.getService(eq(registryServiceReference))).thenReturn(registryService); when(context.registerService(eq(Launcher.class.getName()), any(), (Dictionary) isNull())). thenReturn(launcherServiceRegistration); @@ -116,32 +136,95 @@ tracker = mock(MultipleServiceTracker.class); whenNew(MultipleServiceTracker.class). withParameterTypes(BundleContext.class, Class[].class, Action.class). - withArguments(eq(context), eq(new Class[] {OSGiRegistry.class, Keyring.class}), + withArguments(eq(context), eq(new Class[] {BundleManager.class, Keyring.class}), isA(Action.class)).thenReturn(tracker); } @Test public void testActivatorLifecycle() throws Exception { + ArgumentCaptor<RegisterLauncherCustomizer> customizerCaptor = ArgumentCaptor.forClass(RegisterLauncherCustomizer.class); + ServiceTracker mockTracker = mock(ServiceTracker.class); + whenNew(ServiceTracker.class).withParameterTypes(BundleContext.class, Class.class, ServiceTrackerCustomizer.class).withArguments(eq(context), + any(Keyring.class), customizerCaptor.capture()).thenReturn(mockTracker); + Activator activator = new Activator(); - activator.start(context); Hashtable<String, Object> props = new Hashtable<>(); props.put(ServiceRegistry.SERVICE_NAME, "help"); verify(context).registerService(eq(Command.class.getName()), isA(HelpCommand.class), eq(props)); - ArgumentCaptor<Action> actionCaptor = ArgumentCaptor.forClass(Action.class); - verifyNew(MultipleServiceTracker.class).withArguments(eq(context), - eq(new Class[] {OSGiRegistry.class, Keyring.class}), - actionCaptor.capture()); - Action action = actionCaptor.getValue(); + verify(mockTracker).open(); + + RegisterLauncherCustomizer customizer = customizerCaptor.getValue(); + assertNotNull(customizer); + activator.stop(context); + verify(mockTracker).close(); + } + + @Test + public void testServiceTrackerCustomizer() throws Exception { + StubBundleContext context = new StubBundleContext(); + ArgumentCaptor<RegisterLauncherCustomizer> customizerCaptor = ArgumentCaptor.forClass(RegisterLauncherCustomizer.class); + ServiceTracker mockTracker = mock(ServiceTracker.class); + whenNew(ServiceTracker.class).withParameterTypes(BundleContext.class, Class.class, ServiceTrackerCustomizer.class).withArguments(eq(context), + any(Keyring.class), customizerCaptor.capture()).thenReturn(mockTracker); + + Activator activator = new Activator(); + context.registerService(Keyring.class, mock(Keyring.class), null); + activator.start(context); + + assertTrue(context.isServiceRegistered(Command.class.getName(), HelpCommand.class)); + + RegisterLauncherCustomizer customizer = customizerCaptor.getValue(); + assertNotNull(customizer); + Keyring keyringService = mock(Keyring.class); + context.registerService(Keyring.class, keyringService, null); + ServiceReference ref = context.getServiceReference(Keyring.class); + customizer.addingService(ref); + + assertTrue(context.isServiceRegistered(CommandInfoSource.class.getName(), mock(CommandInfoSourceImpl.class).getClass())); + assertTrue(context.isServiceRegistered(BundleManager.class.getName(), BundleManagerImpl.class)); + assertTrue(context.isServiceRegistered(Launcher.class.getName(), LauncherImpl.class)); - action.dependenciesAvailable(isA(Map.class)); - verify(context).registerService(eq(Launcher.class.getName()), isA(Launcher.class), (Dictionary) isNull()); + customizer.removedService(null, null); + + assertFalse(context.isServiceRegistered(CommandInfoSource.class.getName(), CommandInfoSourceImpl.class)); + assertFalse(context.isServiceRegistered(BundleManager.class.getName(), BundleManagerImpl.class)); + assertFalse(context.isServiceRegistered(Launcher.class.getName(), LauncherImpl.class)); + } + + private Path createStubThermostatHome() throws Exception { + Path tempDir = Files.createTempDirectory("test"); + tempDir.toFile().deleteOnExit(); + System.setProperty("THERMOSTAT_HOME", tempDir.toString()); + + File tempEtc = new File(tempDir.toFile(), "etc"); + tempEtc.mkdirs(); + tempEtc.deleteOnExit(); + + File tempProps = new File(tempEtc, "osgi-export.properties"); + tempProps.createNewFile(); + tempProps.deleteOnExit(); - activator.stop(context); - // osgi will take care of unregistration on bundle stop - // verify(launcherServiceRegistration).unregister(); - verify(tracker).close(); + File tempBundleProps = new File(tempEtc, "bundles.properties"); + tempBundleProps.createNewFile(); + tempBundleProps.deleteOnExit(); + + File tempLibs = new File(tempDir.toFile(), "libs"); + tempLibs.mkdirs(); + tempLibs.deleteOnExit(); + return tempDir; + } + + private void setupOsgiRegistryImplMock() { + PowerMockito.mockStatic(FrameworkUtil.class); + Bundle mockBundle = mock(Bundle.class); + when(FrameworkUtil.getBundle(BundleManagerImpl.class)).thenReturn(mockBundle); + when(mockBundle.getBundleContext()).thenReturn(context); + Bundle mockFramework = mock(Framework.class); + when(context.getBundle(0)).thenReturn(mockFramework); + when(mockFramework.getBundleContext()).thenReturn(context); + when(context.getBundles()).thenReturn(new Bundle[0]); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleLoaderTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,103 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher.internal; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; + +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.launch.Framework; + +import com.redhat.thermostat.launcher.internal.BundleLoader; +import com.redhat.thermostat.test.Bug; + +public class BundleLoaderTest { + + @Test + public void verifyBundlesAreInstalledAndStarted() throws BundleException { + final String BUNDLE_LOCATION = "bundle-location-1"; + + Bundle bundle = mock(Bundle.class); + when(bundle.getHeaders()).thenReturn(new Hashtable<String, String>()); + BundleContext bundleContext = mock(BundleContext.class); + when(bundleContext.installBundle(BUNDLE_LOCATION)).thenReturn(bundle); + Framework framework = mock(Framework.class); + when(framework.getBundleContext()).thenReturn(bundleContext); + List<String> bundleLocations = Arrays.asList(BUNDLE_LOCATION); + + BundleLoader loader = new BundleLoader(); + loader.installAndStartBundles(framework, bundleLocations); + + verify(bundle).start(Bundle.START_TRANSIENT); + } + + @Bug(id="1227", + summary="Make sure launcher does not start fragments", + url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1227") + @Test + public void verifyFragmentsAreInstalledButNotStarted() throws BundleException { + final String BUNDLE_LOCATION = "bundle-location-1"; + + Bundle bundle = mock(Bundle.class); + Dictionary<String, String> bundleHeaders = new Hashtable<>(); + bundleHeaders.put(Constants.FRAGMENT_HOST, "foo-bar"); + when(bundle.getHeaders()).thenReturn(bundleHeaders); + + BundleContext bundleContext = mock(BundleContext.class); + when(bundleContext.installBundle(BUNDLE_LOCATION)).thenReturn(bundle); + Framework framework = mock(Framework.class); + when(framework.getBundleContext()).thenReturn(bundleContext); + List<String> bundleLocations = Arrays.asList(BUNDLE_LOCATION); + + BundleLoader loader = new BundleLoader(); + loader.installAndStartBundles(framework, bundleLocations); + + verify(bundle, times(0)).start(Bundle.START_TRANSIENT); + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BundleManagerImplTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,157 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher.internal; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.whenNew; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.launch.Framework; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.redhat.thermostat.common.Configuration; +import com.redhat.thermostat.common.cli.CommandInfo; +import com.redhat.thermostat.common.cli.CommandInfoSource; +import com.redhat.thermostat.launcher.internal.BundleLoader; +import com.redhat.thermostat.launcher.internal.BundleManagerImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({BundleManagerImpl.class, FrameworkUtil.class}) +public class BundleManagerImplTest { + + private static final String cmdName = "one"; + + private static final String jar1Name = "/one.jar"; + private static final String jar2Name = "/two.jar"; + private static final String jar3Name = "/three.jar"; + + private Bundle b1, b2, b3; + private List<String> bundleLocs; + + private BundleLoader loader; + private Configuration conf; + + @Before + public void setUp() throws Exception { + conf = mock(Configuration.class); + when(conf.getThermostatHome()).thenReturn("no_matter"); + bundleLocs = Arrays.asList(jar1Name, jar2Name, jar3Name); + b1 = mock(Bundle.class); + when(b1.getLocation()).thenReturn(jar1Name); + when(b1.getState()).thenReturn(Bundle.ACTIVE); + b2 = mock(Bundle.class); + when(b2.getLocation()).thenReturn(jar2Name); + when(b2.getState()).thenReturn(Bundle.ACTIVE); + b3 = mock(Bundle.class); + when(b3.getLocation()).thenReturn(jar3Name); + when(b3.getState()).thenReturn(Bundle.ACTIVE); + List<Bundle> installed = Arrays.asList(b1, b2, b3); + + loader = mock(BundleLoader.class); + when(loader.installAndStartBundles(any(Framework.class), eq(bundleLocs))). + thenReturn(installed); + whenNew(BundleLoader.class).withParameterTypes(Boolean.TYPE). + withArguments(any()).thenReturn(loader); + } + + @Test + public void testLoadBundlesFor() throws Exception { + verifyBundlesLoaded(new Bundle[] {}, bundleLocs); + } + + @Test + public void verifyAlreadyLoadedBundlesNotReloaded() throws Exception { + verifyBundlesLoaded(new Bundle[] {b1, b2}, Arrays.asList(jar3Name)); + } + + private void verifyBundlesLoaded(Bundle[] preloaded, List<String> locationsNeeded) throws Exception { + Bundle theBundle = b2; + BundleContext theContext = mock(BundleContext.class); + when(theContext.getBundles()).thenReturn(preloaded); + Framework theFramework = mock(Framework.class); + when(theFramework.getBundleContext()).thenReturn(theContext); + when(theContext.getBundle(0)).thenReturn(theFramework); + when(theBundle.getBundleContext()).thenReturn(theContext); + mockStatic(FrameworkUtil.class); + when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle); + + BundleManagerImpl registry = new BundleManagerImpl(conf); + CommandInfoSource infos = mock(CommandInfoSource.class); + CommandInfo info = mock(CommandInfo.class); + when (info.getDependencyResourceNames()).thenReturn(bundleLocs); + when (infos.getCommandInfo(cmdName)).thenReturn(info); + registry.setCommandInfoSource(infos); + registry.addBundlesFor(cmdName); + verify(loader).installAndStartBundles(any(Framework.class), eq(locationsNeeded)); + } + + @Test + public void verifySetOSGiVerbosityByReflection() throws Exception { + + // All this fluff is just so constructor doesn't NPE. + Bundle theBundle = b2; + BundleContext theContext = mock(BundleContext.class); + when(theContext.getBundles()).thenReturn(new Bundle[]{}); + Framework theFramework = mock(Framework.class); + when(theFramework.getBundleContext()).thenReturn(theContext); + when(theContext.getBundle(0)).thenReturn(theFramework); + when(theBundle.getBundleContext()).thenReturn(theContext); + mockStatic(FrameworkUtil.class); + when(FrameworkUtil.getBundle(any(Class.class))).thenReturn(theBundle); + + Object registry = new BundleManagerImpl(conf); + Class clazz = registry.getClass(); + Method m = clazz.getMethod("setPrintOSGiInfo", Boolean.TYPE); + m.invoke(registry, true); // If this fails, then API has changed in ways that break FrameworkProvider. + } + +}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -72,7 +72,6 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import com.redhat.thermostat.bundles.OSGiRegistry; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ActionNotifier; import com.redhat.thermostat.common.ApplicationInfo; @@ -93,6 +92,7 @@ import com.redhat.thermostat.common.tools.ApplicationState; import com.redhat.thermostat.common.tools.BasicCommand; import com.redhat.thermostat.common.utils.OSGIUtils; +import com.redhat.thermostat.launcher.BundleManager; import com.redhat.thermostat.launcher.internal.LauncherImpl.LoggingInitializer; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.test.StubBundleContext; @@ -144,7 +144,7 @@ private StubBundleContext bundleContext; private Bundle sysBundle; private TestTimerFactory timerFactory; - private OSGiRegistry registry; + private BundleManager registry; private LoggingInitializer loggingInitializer; private DbServiceFactory dbServiceFactory; private CommandInfoSource infos; @@ -211,7 +211,7 @@ ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(new HelpCommand(), cmd1, cmd2, cmd3, basicCmd)); - registry = mock(OSGiRegistry.class); + registry = mock(BundleManager.class); infos = mock(CommandInfoSource.class); when(infos.getCommandInfo(name1)).thenReturn(info1);
--- a/main/pom.xml Wed Jan 09 14:59:30 2013 -0500 +++ b/main/pom.xml Mon Jan 14 14:04:50 2013 -0500 @@ -84,11 +84,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-bundles</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-launcher</artifactId> <version>${project.version}</version> </dependency>
--- a/main/src/main/java/com/redhat/thermostat/main/Thermostat.java Wed Jan 09 14:59:30 2013 -0500 +++ b/main/src/main/java/com/redhat/thermostat/main/Thermostat.java Mon Jan 14 14:04:50 2013 -0500 @@ -62,6 +62,7 @@ this.context = context; } + @SuppressWarnings({ "rawtypes", "unchecked" }) private void launch() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, FileNotFoundException, IOException, BundleException, InterruptedException {
--- a/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java Wed Jan 09 14:59:30 2013 -0500 +++ b/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java Mon Jan 14 14:04:50 2013 -0500 @@ -59,10 +59,9 @@ import org.osgi.framework.launch.FrameworkFactory; import org.osgi.util.tracker.ServiceTracker; -import com.redhat.thermostat.bundles.OSGiRegistry; import com.redhat.thermostat.common.Configuration; -import com.redhat.thermostat.common.ConfigurationException; import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.launcher.BundleManager; public class FrameworkProvider { @@ -217,11 +216,11 @@ locations.add(location); } } - OSGiRegistry.preLoadBundles(framework, locations, printOSGiInfo); + BundleManager.preLoadBundles(framework, locations, printOSGiInfo); } private void setLoaderVerbosity(Framework framework) throws InterruptedException { - Object loader = getService(framework, OSGiRegistry.class.getName()); + Object loader = getService(framework, BundleManager.class.getName()); callVoidReflectedMethod(loader, "setPrintOSGiInfo", printOSGiInfo, Boolean.TYPE); } @@ -232,6 +231,7 @@ private Object getService(Framework framework, String name) throws InterruptedException { Object service = null; + @SuppressWarnings({ "unchecked", "rawtypes" }) ServiceTracker tracker = new ServiceTracker(framework.getBundleContext(), name, null); tracker.open(); service = tracker.waitForService(0);
--- a/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties Wed Jan 09 14:59:30 2013 -0500 +++ b/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties Mon Jan 14 14:04:50 2013 -0500 @@ -1,7 +1,6 @@ bundles=thermostat-keyring-${project.version}.jar, \ thermostat-storage-core-${project.version}.jar, \ thermostat-common-core-${project.version}.jar, \ - thermostat-bundles-${project.version}.jar, \ thermostat-launcher-${project.version}.jar, \ thermostat-main-${project.version}.jar, \ jline2.jar, \
--- a/main/src/test/java/com/redhat/thermostat/main/ThermostatTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/main/src/test/java/com/redhat/thermostat/main/ThermostatTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -36,27 +36,36 @@ package com.redhat.thermostat.main; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Hashtable; import org.junit.Before; +import org.junit.Test; import org.junit.runner.RunWith; +import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.launch.Framework; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import com.redhat.thermostat.bundles.impl.OSGiRegistryImpl; -import com.redhat.thermostat.common.Configuration; +import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.launcher.BundleManager; +import com.redhat.thermostat.main.impl.FrameworkProvider; @RunWith(PowerMockRunner.class) -@PrepareForTest(value = Thermostat.class) +@PrepareForTest({FrameworkProvider.class}) public class ThermostatTest { private Path tempDir; @@ -65,12 +74,9 @@ private BundleContext mockContext; + @SuppressWarnings("rawtypes") @Before public void setUp() throws Exception { - - final OSGiRegistryImpl osgiRegistry = mock(OSGiRegistryImpl.class); - PowerMockito.whenNew(OSGiRegistryImpl.class).withArguments(any(Configuration.class)).thenReturn(osgiRegistry); - tempDir = Files.createTempDirectory("test"); tempDir.toFile().deleteOnExit(); System.setProperty("THERMOSTAT_HOME", tempDir.toString()); @@ -93,19 +99,40 @@ mockContext = mock(BundleContext.class); - mockFramework = mock(Framework.class); - when(mockFramework.getBundleContext()).thenReturn(mockContext); - - TestFrameworkFactory.setFramework(mockFramework); + Framework framework = mock(Framework.class); + TestFrameworkFactory.setFramework(framework); + when(framework.getBundleContext()).thenReturn(mockContext); + Bundle mockBundle = mock(Bundle.class); + when(mockContext.installBundle(any(String.class))).thenReturn(mockBundle); + when(mockBundle.getHeaders()).thenReturn(new Hashtable<String, String>()); + ServiceTracker registryTracker = mock(ServiceTracker.class); + PowerMockito + .whenNew(ServiceTracker.class) + .withParameterTypes(BundleContext.class, String.class, + ServiceTrackerCustomizer.class) + .withArguments(any(BundleContext.class), + eq(BundleManager.class.getName()), any(ServiceTrackerCustomizer.class)) + .thenReturn(registryTracker); + when(registryTracker.waitForService(0)).thenReturn(mock(BundleManager.class)); + ServiceTracker launcherTracker = mock(ServiceTracker.class); + Launcher launcher = mock(Launcher.class); + PowerMockito + .whenNew(ServiceTracker.class) + .withParameterTypes(BundleContext.class, String.class, + ServiceTrackerCustomizer.class) + .withArguments(any(BundleContext.class), + eq(Launcher.class.getName()), + any(ServiceTrackerCustomizer.class)) + .thenReturn(launcherTracker); + when(launcherTracker.waitForService(0)) + .thenReturn(launcher); } - // TODO These now seem to belong in OSGiRegistryTest - - /* @Test public void testOSGIDirExists() throws Exception { - Path osgiDir = tempDir.resolve("osgi"); + Path osgiDir = tempDir.resolve("osgi-cache"); osgiDir.toFile().mkdirs(); + osgiDir.toFile().deleteOnExit(); assertTrue(osgiDir.toFile().exists()); try { Thermostat.main(new String[0]); @@ -113,20 +140,18 @@ e.printStackTrace(); } assertTrue(osgiDir.toFile().exists()); - }*/ - - /*@Test - public void testFrameworkConfig() throws Exception { - Thermostat.main(new String[0]); - Map<String,String> config = TestFrameworkFactory.getConfig(); - Path osgiDir = tempDir.resolve("osgi"); - assertEquals(osgiDir.toString(), config.get(Constants.FRAMEWORK_STORAGE)); } @Test public void testFrameworkInitAndStart() throws Exception { + Path osgiDir = tempDir.resolve("osgi-cache"); + osgiDir.toFile().mkdirs(); + osgiDir.toFile().deleteOnExit(); + mockFramework = mock(Framework.class); + when(mockFramework.getBundleContext()).thenReturn(mockContext); + TestFrameworkFactory.setFramework(mockFramework); Thermostat.main(new String[0]); verify(mockFramework).init(); verify(mockFramework).start(); - }*/ + } }
--- a/main/src/test/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactory Wed Jan 09 14:59:30 2013 -0500 +++ b/main/src/test/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactory Mon Jan 14 14:04:50 2013 -0500 @@ -34,4 +34,4 @@ # to do so, delete this exception statement from your version. # -com.redhat.thermostat.launcher.TestFrameworkFactory \ No newline at end of file +com.redhat.thermostat.main.TestFrameworkFactory \ No newline at end of file
--- a/pom.xml Wed Jan 09 14:59:30 2013 -0500 +++ b/pom.xml Mon Jan 14 14:04:50 2013 -0500 @@ -120,7 +120,6 @@ <module>distribution</module> <module>main</module> <module>launcher</module> - <module>bundles</module> <module>common</module> <module>agent</module> <module>client</module>
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/AbstractQuery.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/AbstractQuery.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,7 +41,9 @@ import java.util.List; import java.util.Objects; -public abstract class AbstractQuery implements Query { +import com.redhat.thermostat.storage.model.Pojo; + +public abstract class AbstractQuery<T extends Pojo> implements Query<T> { public static class Sort { private Key<?> key; @@ -93,9 +95,8 @@ } @Override - public <T> Query sort(Key<T> key, SortDirection direction) { + public void sort(Key<?> key, SortDirection direction) { sorts.add(new Sort(key, direction)); - return this; } public List<Sort> getSorts() { @@ -107,9 +108,8 @@ } @Override - public Query limit(int limit) { + public void limit(int limit) { this.limit = limit; - return this; } public int getLimit() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Add.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,42 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.storage.core; + +public interface Add extends Put { + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/BasePut.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.storage.core; + +import com.redhat.thermostat.storage.model.Pojo; + + +public abstract class BasePut implements Put { + + private Category category; + private Pojo pojo; + + public final void setCategory(Category category) { + if (this.category != null) { + throw new IllegalStateException(); + } + this.category = category; + } + + public final Category getCategory() { + return category; + } + + @Override + public final void setPojo(Pojo pojo) { + this.pojo = pojo; + } + + public final Pojo getPojo() { + return pojo; + } + +}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Category.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Category.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,15 +42,20 @@ import java.util.Map; import java.util.Objects; +import com.redhat.thermostat.storage.model.Pojo; + /** * A bag of data */ -public class Category { +public class Category<T extends Pojo> { + private String name; private final Map<String, Key<?>> keys; + private transient Class<T> dataClass; + private String dataClassName; public Category() { - this(null); + this(null, null); } /** @@ -60,20 +65,21 @@ * * @throws IllegalArgumentException if a Category is created with a name that has been used before */ - public Category(String name, Key<?>... keys) { + public Category(String name, Class<T> dataClass, Key<?>... keys) { Map<String, Key<?>> keysMap = new HashMap<String, Key<?>>(); for (Key<?> key : keys) { keysMap.put(key.getName(), key); } this.keys = Collections.unmodifiableMap(keysMap); setName(name); + setDataClass(dataClass); } public String getName() { return name; } - public void setName(String name) { + private void setName(String name) { if (Categories.contains(name)) { throw new IllegalStateException(); } @@ -85,6 +91,29 @@ } } + private void setDataClass(Class<T> dataClass) { + this.dataClass = dataClass; + if (dataClass != null) { + dataClassName = dataClass.getName(); + } + } + + public Class<T> getDataClass() { + if (dataClass == null && dataClassName != null) { + initializeDataClassFromName(); + } + return dataClass; + } + + @SuppressWarnings("unchecked") + private void initializeDataClassFromName() { + try { + dataClass = (Class<T>) Class.forName(dataClassName); + } catch (ClassNotFoundException e) { + throw new StorageException(e); + } + } + public synchronized Collection<Key<?>> getKeys() { return keys.values(); } @@ -105,7 +134,7 @@ if (! (o instanceof Category)) { return false; } - Category other = (Category) o; + Category<?> other = (Category<?>) o; return Objects.equals(name, other.name) && Objects.equals(keys, other.keys); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Put.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,59 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.storage.core; + +import com.redhat.thermostat.storage.model.Pojo; + + +public interface Put { + + /** + * Sets the POJO that is to be put into the database. + * Notice that this is usually not necessary to call, because Storage.add() + * and Storage.replace() already take this argument. It is useful + * for pre-building and caching queries though. + * + * @param the pojo to be put into the database + */ + void setPojo(Pojo pojo); + + /** + * Applies this put operation to the database. + */ + void apply(); +}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Query.java Mon Jan 14 14:04:50 2013 -0500 @@ -36,10 +36,12 @@ package com.redhat.thermostat.storage.core; +import com.redhat.thermostat.storage.model.Pojo; + /** * Describes what data should be fetched. */ -public interface Query { +public interface Query<T extends Pojo> { enum Criteria { EQUALS, @@ -65,11 +67,12 @@ } } - Query from(Category category); + <S> void where(Key<S> key, Criteria criteria, S value); - <T> Query where(Key<T> key, Criteria criteria, T value); + void sort(Key<?> key, SortDirection direction); - <T> Query sort(Key<T> key, SortDirection direction); + void limit(int n); - Query limit(int n); + Cursor<T> execute(); + }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,11 +42,60 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import com.redhat.thermostat.storage.model.AgentIdPojo; import com.redhat.thermostat.storage.model.Pojo; public final class QueuedStorage implements Storage { + private class QueuedReplace extends BasePut implements Replace { + + @Override + public void apply() { + replaceImpl(getCategory(), getPojo()); + } + + } + + private class QueuedAdd extends BasePut implements Add { + + @Override + public void apply() { + addImpl(getCategory(), getPojo()); + } + + } + + private class QueuedUpdate implements Update { + private Update delegateUpdate; + + QueuedUpdate(Update delegateUpdate) { + this.delegateUpdate = delegateUpdate; + } + + @Override + public <T> void where(Key<T> key, T value) { + delegateUpdate.where(key, value); + + } + + @Override + public <T> void set(Key<T> key, T value) { + delegateUpdate.set(key, value); + } + + @Override + public void apply() { + executor.execute(new Runnable() { + + @Override + public void run() { + delegateUpdate.apply(); + } + + }); + } + + } + private Storage delegate; private ExecutorService executor; private ExecutorService fileExecutor; @@ -79,27 +128,43 @@ } @Override - public void putPojo(final Category category, final boolean replace, final AgentIdPojo pojo) { + public Add createAdd(Category<?> into) { + QueuedAdd add = new QueuedAdd(); + add.setCategory(into); + return add; + } + @Override + public Replace createReplace(Category<?> into) { + QueuedReplace replace = new QueuedReplace(); + replace.setCategory(into); + return replace; + } + + private void replaceImpl(final Category<?> category, final Pojo pojo) { + executor.execute(new Runnable() { @Override public void run() { - delegate.putPojo(category, replace, pojo); + Replace replace = delegate.createReplace(category); + replace.setPojo(pojo); + replace.apply(); } }); } - @Override - public void updatePojo(final Update update) { - + private void addImpl(final Category<?> category, final Pojo pojo) { + executor.execute(new Runnable() { @Override public void run() { - delegate.updatePojo(update); + Add add = delegate.createAdd(category); + add.setPojo(pojo); + add.apply(); } }); @@ -134,14 +199,8 @@ } - @Override - public <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass) { - return delegate.findAllPojos(query, resultClass); - } - - @Override - public <T extends Pojo> T findPojo(Query query, Class<T> resultClass) { - return delegate.findPojo(query, resultClass); + <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass) { + return query.execute(); } @Override @@ -169,13 +228,14 @@ } @Override - public Query createQuery() { - return delegate.createQuery(); + public <T extends Pojo> Query<T> createQuery(Category<T> category) { + return delegate.createQuery(category); } @Override - public Update createUpdate() { - return delegate.createUpdate(); + public Update createUpdate(Category<?> category) { + QueuedUpdate update = new QueuedUpdate(delegate.createUpdate(category)); + return update; } @Override @@ -203,7 +263,7 @@ } @Override - public void registerCategory(final Category category) { + public void registerCategory(final Category<?> category) { delegate.registerCategory(category); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Replace.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,42 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.storage.core; + +public interface Replace extends Put { + +}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java Mon Jan 14 14:04:50 2013 -0500 @@ -39,7 +39,6 @@ import java.io.InputStream; import java.util.UUID; -import com.redhat.thermostat.storage.model.AgentIdPojo; import com.redhat.thermostat.storage.model.Pojo; /** @@ -53,15 +52,12 @@ String getAgentId(); - void registerCategory(Category category); + void registerCategory(Category<?> category); Connection getConnection(); - // TODO why does putPojo have an agent id param but not updatePojo and removePojo? - - void putPojo(Category category, boolean replace, AgentIdPojo pojo); - - void updatePojo(Update update); + Add createAdd(Category<?> category); + Replace createReplace(Category<?> category); void removePojo(Remove remove); @@ -70,20 +66,18 @@ */ void purge(); - <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass); - - <T extends Pojo> T findPojo(Query query, Class<T> resultClass); - - long getCount(Category category); + long getCount(Category<?> category); void saveFile(String filename, InputStream data); InputStream loadFile(String filename); - Query createQuery(); - Update createUpdate(); + <T extends Pojo> Query<T> createQuery(Category<T> category); + + Update createUpdate(Category<?> category); Remove createRemove(); + void shutdown(); }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Update.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Update.java Mon Jan 14 14:04:50 2013 -0500 @@ -37,11 +37,35 @@ package com.redhat.thermostat.storage.core; /** - * Describes which data should be updated with what values + * Updates fields of a database entry. */ public interface Update { - Update from(Category category); - <T> Update where(Key<T> key, T value); - <T> Update set(Key<T> key, T value); + /** + * Adds a where clause that denotes the entry to be updated. If more than one + * where-clause is declared, they are concatenated as an and-query. + * If a clause with the same key is declared more than once, the latter + * overrides the former. This is so that an Update object can be reused + * for multiple requests. If an update is issued for which no entry can + * be found (i.e. the where-clause yields no results), a + * <code>StorageException</code> may get thrown. + * + * @param key the key of the field of the where clause + * @param value the value of the field of the where clause + */ + <T> void where(Key<T> key, T value); + + /** + * Sets a field in a found document to the specified value. If the same key is + * set more than once, the latest values overrides the former values. + * + * @param key the key of the field + * @param value the value to set + */ + <T> void set(Key<T> key, T value); + + /** + * Applies the update operation. + */ + void apply(); }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/AgentIdPojo.java Wed Jan 09 14:59:30 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - - -package com.redhat.thermostat.storage.model; - -public interface AgentIdPojo extends Pojo { - - void setAgentId(String agentId); - String getAgentId(); -}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/BasePojo.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/BasePojo.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,7 +41,7 @@ import com.redhat.thermostat.storage.core.Persist; -public class BasePojo implements AgentIdPojo { +public class BasePojo implements Pojo { private String agentId;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/BasePutTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -0,0 +1,94 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.storage.core; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.storage.model.Pojo; + +public class BasePutTest { + + private BasePut insert; + + @Before + public void setUp() { + insert = new BasePut() { + public void apply() { + // Do nothing. + } + }; + } + + @After + public void tearDown() { + insert = null; + } + + @Test + public void testCategory() { + Category category = mock(Category.class); + + assertNull(insert.getCategory()); + insert.setCategory(category); + assertSame(category, insert.getCategory()); + + try { + insert.setCategory(category); + fail(); + } catch (IllegalStateException ex) { + // Ok. + } + } + + @Test + public void testPojo() { + Pojo pojo = mock(Pojo.class); + + assertNull(insert.getPojo()); + insert.setPojo(pojo); + assertSame(pojo, insert.getPojo()); + + } +}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/CategoryTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/CategoryTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -44,22 +44,25 @@ import org.junit.Test; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.model.Pojo; public class CategoryTest { + private static class TestObj implements Pojo { + // Dummy class for testing. + } + @Test public void testGetKey() { Key<String> key1 = new Key<String>("key1", false); - Category category = new Category("testGetKey", key1); + Category<TestObj> category = new Category<>("testGetKey", TestObj.class, key1); assertEquals(key1, category.getKey("key1")); } @Test public void testGetNonExistingKey() { Key<String> key1 = new Key<String>("key1", false); - Category category = new Category("testGetNonExistingKey", key1); + Category<TestObj> category = new Category<>("testGetNonExistingKey", TestObj.class, key1); assertNull(category.getKey("key2")); } @@ -69,7 +72,7 @@ Key<String> key2 = new Key<String>("key2", false); Key<String> key3 = new Key<String>("key3", false); Key<String> key4 = new Key<String>("key4", false); - Category category = new Category("testGetKeys", key1, key2, key3, key4); + Category<TestObj> category = new Category<>("testGetKeys", TestObj.class, key1, key2, key3, key4); assertEquals(4, category.getKeys().size()); assertTrue(category.getKeys().contains(key1)); assertTrue(category.getKeys().contains(key2)); @@ -82,7 +85,7 @@ Key<String> key1 = new Key<String>("key1", false); Key<String> key2 = new Key<String>("key2", false); Key<String> key3 = new Key<String>("key3", false); - Category category = new Category("verifyThatKeysAreUnmodifiable", key1, key2, key3); + Category<TestObj> category = new Category<>("verifyThatKeysAreUnmodifiable", TestObj.class, key1, key2, key3); Collection<Key<?>> keys = category.getKeys();
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -67,7 +67,6 @@ import org.junit.Before; import org.junit.Test; -import com.redhat.thermostat.storage.model.AgentIdPojo; import com.redhat.thermostat.storage.model.Pojo; @@ -165,6 +164,7 @@ // Not used. return null; } + } private static class TestPojo implements Pojo { @@ -173,13 +173,15 @@ private QueuedStorage queuedStorage; private Storage delegateStorage; + private Add delegateAdd; + private Replace delegateReplace; + private Query<?> delegateQuery; private TestExecutor executor; private TestExecutor fileExecutor; @SuppressWarnings("rawtypes") private Cursor expectedResults; - private TestPojo expectedResult; private InputStream expectedFile; @SuppressWarnings("unchecked") @@ -188,16 +190,18 @@ executor = new TestExecutor(); fileExecutor = new TestExecutor(); delegateStorage = mock(Storage.class); - Update update = mock(Update.class); + + delegateAdd = mock(Add.class); + delegateReplace = mock(Replace.class); + Remove remove = mock(Remove.class); - Query query = mock(Query.class); - when(delegateStorage.createUpdate()).thenReturn(update); + delegateQuery = mock(Query.class); + when(delegateStorage.createAdd(any(Category.class))).thenReturn(delegateAdd); + when(delegateStorage.createReplace(any(Category.class))).thenReturn(delegateReplace); when(delegateStorage.createRemove()).thenReturn(remove); - when(delegateStorage.createQuery()).thenReturn(query); + when(delegateStorage.createQuery(any(Category.class))).thenReturn(delegateQuery); expectedResults = mock(Cursor.class); - when(delegateStorage.findAllPojos(query, TestPojo.class)).thenReturn(expectedResults); - expectedResult = new TestPojo(); - when(delegateStorage.findPojo(query, TestPojo.class)).thenReturn(expectedResult); + when(delegateQuery.execute()).thenReturn(expectedResults); when(delegateStorage.getCount(any(Category.class))).thenReturn(42l); expectedFile = mock(InputStream.class); when(delegateStorage.loadFile(anyString())).thenReturn(expectedFile); @@ -209,26 +213,32 @@ @After public void tearDown() { expectedFile = null; - expectedResult = null; expectedResults = null; queuedStorage = null; delegateStorage = null; fileExecutor = null; executor = null; + delegateQuery = null; } @Test - public void testPutPojo() { - Category category = mock(Category.class); - AgentIdPojo pojo = mock(AgentIdPojo.class); + public void testInsert() { + Category<?> category = mock(Category.class); + Pojo pojo = mock(Pojo.class); - queuedStorage.putPojo(category, true, pojo); + Put put = queuedStorage.createReplace(category); + put.setPojo(pojo); + put.apply(); Runnable r = executor.getTask(); assertNotNull(r); verifyZeroInteractions(delegateStorage); + verifyZeroInteractions(delegateReplace); + r.run(); - verify(delegateStorage, times(1)).putPojo(category, true, pojo); + verify(delegateStorage).createReplace(category); + verify(delegateReplace).setPojo(pojo); + verify(delegateReplace).apply(); verifyNoMoreInteractions(delegateStorage); assertNull(fileExecutor.getTask()); @@ -236,19 +246,23 @@ @Test public void testUpdatePojo() { + Update delegateUpdate = mock(Update.class); + when(delegateStorage.createUpdate(any(Category.class))).thenReturn(delegateUpdate); - Update update = queuedStorage.createUpdate(); - verify(delegateStorage).createUpdate(); + Category<?> category = mock(Category.class); + + Update update = queuedStorage.createUpdate(category); + verify(delegateStorage).createUpdate(category); verifyNoMoreInteractions(delegateStorage); - queuedStorage.updatePojo(update); + update.apply(); Runnable r = executor.getTask(); assertNotNull(r); - verifyZeroInteractions(delegateStorage); + verifyZeroInteractions(delegateUpdate); r.run(); - verify(delegateStorage, times(1)).updatePojo(update); - verifyNoMoreInteractions(delegateStorage); + verify(delegateUpdate).apply(); + verifyNoMoreInteractions(delegateUpdate); assertNull(fileExecutor.getTask()); } @@ -289,12 +303,14 @@ @Test public void testFindAllPojos() { - Query query = queuedStorage.createQuery(); - verify(delegateStorage).createQuery(); + @SuppressWarnings("unchecked") + Category<TestPojo> category = mock(Category.class); + Query<TestPojo> query = queuedStorage.createQuery(category); + verify(delegateStorage).createQuery(category); verifyNoMoreInteractions(delegateStorage); - Cursor<TestPojo> result = queuedStorage.findAllPojos(query, TestPojo.class); - verify(delegateStorage).findAllPojos(query, TestPojo.class); + Cursor<TestPojo> result = query.execute(); + verify(delegateQuery).execute(); assertSame(expectedResults, result); assertNull(executor.getTask()); @@ -302,22 +318,8 @@ } @Test - public void testFindPojo() { - Query query = queuedStorage.createQuery(); - verify(delegateStorage).createQuery(); - verifyNoMoreInteractions(delegateStorage); - - TestPojo result = queuedStorage.findPojo(query, TestPojo.class); - verify(delegateStorage).findPojo(query, TestPojo.class); - assertSame(expectedResult, result); - - assertNull(executor.getTask()); - assertNull(fileExecutor.getTask()); - } - - @Test public void testGetCount() { - Category category = mock(Category.class); + Category<?> category = mock(Category.class); long result = queuedStorage.getCount(category); assertEquals(42, result); @@ -380,7 +382,7 @@ @Test public void testRegisterCategory() { - Category category = mock(Category.class); + Category<?> category = mock(Category.class); queuedStorage.registerCategory(category);
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoQuery.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,34 +42,38 @@ import com.mongodb.DBObject; import com.redhat.thermostat.storage.core.AbstractQuery; import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.model.Pojo; -public class MongoQuery extends AbstractQuery { +public class MongoQuery<T extends Pojo> extends AbstractQuery<T> { + private MongoStorage storage; private BasicDBObject query = new BasicDBObject(); private boolean hasClauses = false; - private Category category; + private Category<T> category; + private Class<T> resultClass; - @Override - public MongoQuery from(Category category) { - setCategory(category); - return this; + MongoQuery(MongoStorage storage, Category<T> category) { + this.storage = storage; + this.category = category; + this.resultClass = category.getDataClass(); } - public Category getCategory() { + public Category<T> getCategory() { return category; } - public void setCategory(Category category) { + public void setCategory(Category<T> category) { this.category = category; } @Override - public <T> MongoQuery where(Key<T> key, Criteria operator, T value) { - return where(key.getName(), operator, value); + public <S> void where(Key<S> key, Criteria operator, S value) { + where(key.getName(), operator, value); } - public MongoQuery where(String key, Criteria operator, Object value) { + public void where(String key, Criteria operator, Object value) { switch (operator) { case EQUALS: query.put(key, value); @@ -97,7 +101,6 @@ throw new IllegalArgumentException("MongoQuery can not handle " + operator); } hasClauses = true; - return this; } DBObject getGeneratedQuery() { @@ -115,7 +118,7 @@ if (!(obj instanceof MongoQuery)) { return false; } - MongoQuery other = (MongoQuery) obj; + MongoQuery<?> other = (MongoQuery<?>) obj; return Objects.equals(getCategory(), other.getCategory()) && Objects.equals(this.query, other.query); } @@ -128,4 +131,8 @@ return hasClauses ; } + @Override + public Cursor<T> execute() { + return storage.findAllPojos(this, resultClass); + } }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Mon Jan 14 14:04:50 2013 -0500 @@ -53,6 +53,8 @@ import com.mongodb.gridfs.GridFSInputFile; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.AbstractQuery.Sort; +import com.redhat.thermostat.storage.core.Add; +import com.redhat.thermostat.storage.core.BasePut; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Connection; import com.redhat.thermostat.storage.core.Connection.ConnectionListener; @@ -61,9 +63,9 @@ import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Remove; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.model.AgentIdPojo; import com.redhat.thermostat.storage.model.Pojo; /** @@ -73,7 +75,23 @@ */ public class MongoStorage implements Storage { - public static final String SET_MODIFIER = "$set"; + private class MongoAdd extends BasePut implements Add { + + @Override + public void apply() { + addImpl(getCategory(), getPojo()); + } + + } + + private class MongoReplace extends BasePut implements Replace { + + @Override + public void apply() { + replaceImpl(getCategory(), getPojo()); + } + + } private MongoConnection conn; private DB db = null; @@ -113,52 +131,52 @@ return agentId.toString(); } - private String getAgentQueryKeyFromGlobalAgent() { - if (agentId != null) { - return agentId.toString(); - } else { - return null; - } - } - - private String getAgentQueryKeyFromChunkOrGlobalAgent(AgentIdPojo pojo) { - String queryKey = getAgentQueryKeyFromGlobalAgent(); - if (queryKey != null) { - return queryKey; - } else { - return pojo.getAgentId(); - } + @Override + public Add createAdd(Category<?> into) { + MongoAdd add = new MongoAdd(); + add.setCategory(into); + return add; } @Override - public void putPojo(final Category cat, final boolean replace, final AgentIdPojo pojo) { + public Replace createReplace(Category<?> into) { + MongoReplace replace = new MongoReplace(); + replace.setCategory(into); + return replace; + } + + private void addImpl(final Category<?> cat, final Pojo pojo) { + DBCollection coll = getCachedCollection(cat); + DBObject toInsert = preparePut(pojo); + coll.insert(toInsert); + } + + private void replaceImpl(final Category<?> cat, final Pojo pojo) { DBCollection coll = getCachedCollection(cat); + DBObject toInsert = preparePut(pojo); + + DBObject query = new BasicDBObject(); + Collection<Key<?>> keys = cat.getKeys(); + for (Key<?> key : keys) { + if (key.isPartialCategoryKey()) { + String name = key.getName(); + query.put(name, toInsert.get(name)); + } + } + coll.update(query, toInsert, true, false); + } + + private DBObject preparePut(final Pojo pojo) { MongoPojoConverter converter = new MongoPojoConverter(); DBObject toInsert = converter.convertPojoToMongo(pojo); - String agentId = getAgentQueryKeyFromChunkOrGlobalAgent(pojo); - toInsert.put(Key.AGENT_ID.getName(), agentId); - if (replace) { - // TODO: Split this part out into a separate method. It is a very bad practice to - // completely change the behaviour of a method based on a boolean flag. - DBObject query = new BasicDBObject(); - Collection<Key<?>> keys = cat.getKeys(); - for (Key<?> key : keys) { - if (key.isPartialCategoryKey()) { - String name = key.getName(); - query.put(name, toInsert.get(name)); - } - } - coll.update(query, toInsert, true, false); - } else { - coll.insert(toInsert); + if (toInsert.get(Key.AGENT_ID.getName()) == null) { + toInsert.put(Key.AGENT_ID.getName(), getAgentId()); } + return toInsert; } - @Override - public void updatePojo(Update update) { - assert update instanceof MongoUpdate; - MongoUpdate mongoUpdate = (MongoUpdate) update; - Category cat = mongoUpdate.getCategory(); + void updatePojo(MongoUpdate mongoUpdate) { + Category<?> cat = mongoUpdate.getCategory(); DBCollection coll = getCachedCollection(cat); DBObject query = mongoUpdate.getQuery(); DBObject values = mongoUpdate.getValues(); @@ -170,18 +188,13 @@ assert (remove instanceof MongoRemove); MongoRemove mongoRemove = (MongoRemove) remove; DBObject query = mongoRemove.getQuery(); - Category category = mongoRemove.getCategory(); + Category<?> category = mongoRemove.getCategory(); DBCollection coll = getCachedCollection(category); - String agentId = getAgentQueryKeyFromGlobalAgent(); - if (agentId != null) { - query.put(Key.AGENT_ID.getName(), agentId); - } - coll.remove(query); } - private DBCollection getCachedCollection(Category category) { + private DBCollection getCachedCollection(Category<?> category) { String collName = category.getName(); DBCollection coll = collectionCache.get(collName); if (coll == null && db.collectionExists(collName)) { @@ -193,22 +206,21 @@ // TODO: This method is only temporary to enable tests, until we come up with a better design, // in particular, the collection should be stored in the category itself. It must not be called // from production code. - void mapCategoryToDBCollection(Category category, DBCollection coll) { + void mapCategoryToDBCollection(Category<?> category, DBCollection coll) { collectionCache.put(category.getName(), coll); } @Override public void purge() { - String deleteKey = getAgentQueryKeyFromGlobalAgent(); - BasicDBObject query = new BasicDBObject(Key.AGENT_ID.getName(), deleteKey); + BasicDBObject query = new BasicDBObject(Key.AGENT_ID.getName(), getAgentId()); for (DBCollection coll : collectionCache.values()) { coll.remove(query); } } @Override - public void registerCategory(Category category) { + public void registerCategory(Category<?> category) { String name = category.getName(); if (collectionCache.containsKey(name)) { throw new IllegalStateException("Category may only be associated with one backend."); @@ -224,13 +236,13 @@ } @Override - public Query createQuery() { - return new MongoQuery(); + public <T extends Pojo> Query<T> createQuery(Category<T> category) { + return new MongoQuery<T>(this, category); } @Override - public Update createUpdate() { - return new MongoUpdate(); + public Update createUpdate(Category<?> category) { + return new MongoUpdate(this, category); } @Override @@ -238,9 +250,7 @@ return new MongoRemove(); } - @Override - public <T extends Pojo> Cursor<T> findAllPojos(Query query, Class<T> resultClass) { - MongoQuery mongoQuery = checkAndCastQuery(query); + <T extends Pojo> Cursor<T> findAllPojos(MongoQuery<T> mongoQuery, Class<T> resultClass) { DBCollection coll = getCachedCollection(mongoQuery.getCategory()); DBCursor dbCursor; if (mongoQuery.hasClauses()) { @@ -252,7 +262,7 @@ return new MongoCursor<T>(dbCursor, resultClass); } - private DBCursor applySortAndLimit(MongoQuery query, DBCursor dbCursor) { + private DBCursor applySortAndLimit(MongoQuery<?> query, DBCursor dbCursor) { BasicDBObject orderBy = new BasicDBObject(); List<Sort> sorts = query.getSorts(); for (Sort sort : sorts) { @@ -268,25 +278,7 @@ @Override - public <T extends Pojo> T findPojo(Query query, Class<T> resultClass) { - MongoQuery mongoQuery = checkAndCastQuery(query); - DBCollection coll = getCachedCollection(mongoQuery.getCategory()); - DBObject dbResult = coll.findOne(mongoQuery.getGeneratedQuery()); - MongoPojoConverter conv = new MongoPojoConverter(); - return conv.convertMongoToPojo(dbResult, resultClass); - } - - private MongoQuery checkAndCastQuery(Query query) { - if (!(query instanceof MongoQuery)) { - throw new IllegalArgumentException("MongoStorage can only handle MongoQuery"); - } - - return (MongoQuery) query; - - } - - @Override - public long getCount(Category category) { + public long getCount(Category<?> category) { DBCollection coll = getCachedCollection(category); if (coll != null) { return coll.getCount();
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoUpdate.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoUpdate.java Mon Jan 14 14:04:50 2013 -0500 @@ -43,22 +43,18 @@ import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Update; -// TODO: For now we utilize the Chunk based conversion, and rely on MongoStorage to -// actually resolve the $set fields. Eventually, we want to convert to DBObject -// directly, and take advantage of improved semantics of this class. class MongoUpdate implements Update { + private static final String SET_MODIFIER = "$set"; + + private MongoStorage storage; private DBObject query; private DBObject values; private Category category; - @Override - public Update from(Category category) { - if (query != null || values != null) { - throw new IllegalStateException(); - } + public MongoUpdate(MongoStorage storage, Category category) { + this.storage = storage; this.category = category; - return this; } Category getCategory() { @@ -66,12 +62,11 @@ } @Override - public <T> Update where(Key<T> key, T value) { + public <T> void where(Key<T> key, T value) { if (query == null) { query = new BasicDBObject(); } query.put(key.getName(), value); - return this; } DBObject getQuery() { @@ -79,15 +74,19 @@ } @Override - public <T> Update set(Key<T> key, T value) { + public <T> void set(Key<T> key, T value) { if (values == null) { values = new BasicDBObject(); } values.put(key.getName(), value); - return this; } DBObject getValues() { - return new BasicDBObject("$set", values); + return new BasicDBObject(SET_MODIFIER, values); + } + + @Override + public void apply() { + storage.updatePojo(this); } }
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoCursorTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -52,13 +52,10 @@ import com.mongodb.BasicDBObject; import com.mongodb.DBCursor; import com.mongodb.DBObject; -import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Entity; -import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Persist; import com.redhat.thermostat.storage.model.BasePojo; -import com.redhat.thermostat.storage.mongodb.internal.MongoCursor; public class MongoCursorTest { @@ -102,13 +99,6 @@ } } - private static final Key<String> key1 = new Key<>("key1", false); - private static final Key<String> key2 = new Key<>("key2", false); - private static final Key<String> key3 = new Key<>("key3", false); - private static final Key<String> key4 = new Key<>("key4", false); - - private static final Category testCategory = new Category("MongoCursorTest", key1, key2, key3, key4); - private DBCursor dbCursor; private Cursor<TestClass> cursor;
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoQueryTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -38,28 +38,50 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Query.Criteria; -import com.redhat.thermostat.storage.mongodb.internal.MongoQuery; +import com.redhat.thermostat.storage.model.Pojo; public class MongoQueryTest { + private static class TestClass implements Pojo { + + } + + private static MongoStorage storage; + private static Category<TestClass> category; + + @BeforeClass + public static void setUp() { + storage = mock(MongoStorage.class); + category = new Category<>("some-collection", TestClass.class); + } + + @AfterClass + public static void tearDown() { + storage = null; + category = null; + } + @Test public void testEmptyQuery() { - MongoQuery query = new MongoQuery(); + + MongoQuery<TestClass> query = new MongoQuery<>(storage, category); DBObject mongoQuery = query.getGeneratedQuery(); assertTrue(mongoQuery.keySet().isEmpty()); } @Test public void testCollectionName() { - MongoQuery query = new MongoQuery().from(new Category("some-collection")); + MongoQuery<TestClass> query = new MongoQuery<>(storage, category); assertEquals("some-collection", query.getCategory().getName()); } @@ -100,7 +122,8 @@ } private DBObject generateSimpleWhereQuery(String key, Criteria criteria, Object value) { - MongoQuery query = new MongoQuery().where(key, criteria, value); + MongoQuery<TestClass> query = new MongoQuery<>(storage, category); + query.where(key, criteria, value); return query.getGeneratedQuery(); }
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -74,11 +74,13 @@ import com.mongodb.gridfs.GridFSDBFile; import com.mongodb.gridfs.GridFSInputFile; import com.redhat.thermostat.storage.config.StartupConfiguration; +import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Entity; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Persist; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Update; @@ -142,8 +144,8 @@ private static final Key<String> key3 = new Key<>("key3", false); private static final Key<String> key4 = new Key<>("key4", false); private static final Key<String> key5 = new Key<>("key5", false); - private static final Category testCategory = new Category("MongoStorageTest", key1, key2, key3, key4, key5); - private static final Category emptyTestCategory = new Category("MongoEmptyCategory"); + private static final Category<TestClass> testCategory = new Category<>("MongoStorageTest", TestClass.class, key1, key2, key3, key4, key5); + private static final Category<TestClass> emptyTestCategory = new Category("MongoEmptyCategory", TestClass.class); private StartupConfiguration conf; private Mongo m; @@ -201,57 +203,26 @@ cursor = null; } - @Test (expected=IllegalArgumentException.class) - public void verifyFindOnlyAcceptsMongoQuery() { - MongoStorage storage = makeStorage(); - Query query = mock(Query.class); - storage.findPojo(query, TestClass.class); - } - - @Test (expected=IllegalArgumentException.class) - public void verifyFindAllOnlyAcceptsMongoQuery() { - MongoStorage storage = makeStorage(); - Query query = mock(Query.class); - storage.findAllPojos(query, TestClass.class); - } - @Test public void verifyFindAllReturnsCursor() throws Exception { PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); MongoStorage storage = makeStorage(); - Query query = storage.createQuery().from(testCategory); - Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class); + Query query = storage.createQuery(testCategory); + Cursor<TestClass> cursor = query.execute(); assertNotNull(cursor); } @Test - public void verifyFindReturnsChunk() throws Exception { - PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); - MongoStorage storage = makeStorage(); - Query query = storage.createQuery().from(testCategory).where(key1, Criteria.EQUALS, "test1"); - TestClass result = storage.findPojo(query, TestClass.class); - assertNotNull(result); - } - - @Test public void verifyFindAllCallsDBCollectionFind() throws Exception { PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); MongoStorage storage = makeStorage(); - Query query = storage.createQuery().from(testCategory).where(key1, Criteria.EQUALS, "fluff"); - storage.findAllPojos(query, TestClass.class); + Query query = storage.createQuery(testCategory); + query.where(key1, Criteria.EQUALS, "fluff"); + query.execute(); verify(testCollection).find(any(DBObject.class)); } @Test - public void verifyFindCallsDBCollectionFindOne() throws Exception { - PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); - MongoStorage storage = makeStorage(); - Query query = storage.createQuery().from(testCategory); - storage.findPojo(query, TestClass.class); - verify(testCollection).findOne(any(DBObject.class)); - } - - @Test public void verifyFindAllCallsDBCollectionFindWithCorrectQuery() throws Exception { PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); MongoStorage storage = makeStorage(); @@ -261,45 +232,10 @@ DBObject generatedQuery = mock(DBObject.class); when(query.getGeneratedQuery()).thenReturn(generatedQuery); when(query.getCategory()).thenReturn(testCategory); - ArgumentCaptor<DBObject> findArg = ArgumentCaptor.forClass(DBObject.class); storage.findAllPojos(query, TestClass.class); - verify(testCollection).find(findArg.capture()); - assertSame(generatedQuery, findArg.getValue()); - } - - @Test - public void verifyFindCallsDBCollectionFindOneWithCorrectQuery() throws Exception { - PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); - MongoStorage storage = makeStorage(); - - MongoQuery query = mock(MongoQuery.class); - DBObject generatedQuery = mock(DBObject.class); - when(query.getGeneratedQuery()).thenReturn(generatedQuery); - when(query.getCategory()).thenReturn(testCategory); - - ArgumentCaptor<DBObject> findArg = ArgumentCaptor.forClass(DBObject.class); - - storage.findPojo(query, TestClass.class); - - verify(testCollection).findOne(findArg.capture()); - assertSame(generatedQuery, findArg.getValue()); - } - - @Test - public void verifyFindReturnsCorrectChunk() throws Exception { - PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); - MongoStorage storage = makeStorage(); - // TODO find a way to test this that isn't just testing mock and converters - // Because we mock the DBCollection, the contents of this query don't actually determine the result. - MongoQuery query = new MongoQuery().from(testCategory); - - TestClass result = storage.findPojo(query, TestClass.class); - - assertNotNull(result); - assertEquals("test1", result.getKey1()); - assertEquals("test2", result.getKey2()); + verify(testCollection).find(same(generatedQuery)); } @Test @@ -308,9 +244,8 @@ MongoStorage storage = makeStorage(); // TODO find a way to test this that isn't just testing MongoCursor // Because we mock the DBCollection, the contents of this query don't actually determine the result. - MongoQuery query = new MongoQuery().from(testCategory); - - Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class); + Query query = storage.createQuery(testCategory); + Cursor<TestClass> cursor = query.execute(); verifyDefaultCursor(cursor); } @@ -321,9 +256,11 @@ MongoStorage storage = makeStorage(); // TODO find a way to test this that isn't just testing MongoCursor // Because we mock the DBCollection, the contents of this query don't actually determine the result. - MongoQuery query = (MongoQuery) new MongoQuery().from(testCategory).sort(key1, Query.SortDirection.ASCENDING).limit(3); + Query query = storage.createQuery(testCategory); + query.sort(key1, Query.SortDirection.ASCENDING); + query.limit(3); - Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class); + Cursor<TestClass> cursor = query.execute(); verifyDefaultCursor(cursor); ArgumentCaptor<DBObject> orderBy = ArgumentCaptor.forClass(DBObject.class); @@ -337,8 +274,8 @@ public void verifyFindAllFromCategoryCallsDBCollectionFindAll() throws Exception { PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); MongoStorage storage = makeStorage(); - Query query = storage.createQuery().from(testCategory); - storage.findAllPojos(query, TestClass.class); + Query query = storage.createQuery(testCategory); + query.execute(); verify(testCollection).find(); } @@ -346,8 +283,8 @@ public void verifyFindAllFromCategoryReturnsCorrectCursor() throws Exception { PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); MongoStorage storage = makeStorage(); - Query query = storage.createQuery().from(testCategory); - Cursor<TestClass> cursor = storage.findAllPojos(query, TestClass.class); + Query query = storage.createQuery(testCategory); + Cursor<TestClass> cursor = query.execute(); verifyDefaultCursor(cursor); } @@ -373,7 +310,7 @@ PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m); MongoStorage storage = makeStorage(); storage.getConnection().connect(); - long count = storage.getCount(new Category("NonExistent")); + long count = storage.getCount(new Category("NonExistent", TestClass.class)); assertEquals(0, count); } @@ -413,7 +350,9 @@ MongoStorage storage = makeStorage(); TestClass pojo = new TestClass(); pojo.setAgentId("123"); - storage.putPojo(testCategory, false, pojo); + Put add = storage.createAdd(testCategory); + add.setPojo(pojo); + add.apply(); ArgumentCaptor<DBObject> dbobj = ArgumentCaptor.forClass(DBObject.class); verify(testCollection).insert(dbobj.capture()); DBObject val = dbobj.getValue(); @@ -426,8 +365,9 @@ MongoStorage storage = makeStorage(); storage.setAgentId(new UUID(1, 2)); TestClass pojo = new TestClass(); - pojo.setAgentId("123"); - storage.putPojo(testCategory, false, pojo); + Add add = storage.createAdd(testCategory); + add.setPojo(pojo); + add.apply(); ArgumentCaptor<DBObject> dbobj = ArgumentCaptor.forClass(DBObject.class); verify(testCollection).insert(dbobj.capture()); DBObject val = dbobj.getValue(); @@ -455,8 +395,10 @@ @Test public void verifySimpleUpdate() { MongoStorage storage = makeStorage(); - Update update = storage.createUpdate().from(testCategory).where(Key.AGENT_ID, "test1").set(key2, "test2"); - storage.updatePojo(update); + Update update = storage.createUpdate(testCategory); + update.where(Key.AGENT_ID, "test1"); + update.set(key2, "test2"); + update.apply(); ArgumentCaptor<DBObject> queryCaptor = ArgumentCaptor.forClass(DBObject.class); ArgumentCaptor<DBObject> valueCaptor = ArgumentCaptor.forClass(DBObject.class); @@ -465,13 +407,24 @@ DBObject query = queryCaptor.getValue(); assertTrue(query.containsField(Key.AGENT_ID.getName())); assertEquals("test1", query.get(Key.AGENT_ID.getName())); + + DBObject set = valueCaptor.getValue(); + assertEquals(1, set.keySet().size()); + assertTrue(set.containsField("$set")); + DBObject values = (DBObject) set.get("$set"); + assertEquals(1, values.keySet().size()); + assertTrue(values.containsField(key2.getName())); + assertEquals("test2", values.get(key2.getName())); } @Test public void verifyMultiFieldUpdate() { MongoStorage storage = makeStorage(); - Update update = storage.createUpdate().from(testCategory).where(Key.AGENT_ID, "test1").set(key2, "test2").set(key3, "test3"); - storage.updatePojo(update); + Update update = storage.createUpdate(testCategory); + update.where(Key.AGENT_ID, "test1"); + update.set(key2, "test2"); + update.set(key3, "test3"); + update.apply(); ArgumentCaptor<DBObject> queryCaptor = ArgumentCaptor.forClass(DBObject.class); ArgumentCaptor<DBObject> valueCaptor = ArgumentCaptor.forClass(DBObject.class); @@ -480,9 +433,10 @@ DBObject query = queryCaptor.getValue(); assertTrue(query.containsField(Key.AGENT_ID.getName())); assertEquals("test1", query.get(Key.AGENT_ID.getName())); - DBObject value = valueCaptor.getValue(); - assertTrue(value.containsField("$set")); - DBObject values = (DBObject) value.get("$set"); + + DBObject set = valueCaptor.getValue(); + assertTrue(set.containsField("$set")); + DBObject values = (DBObject) set.get("$set"); assertTrue(values.containsField("key2")); assertEquals("test2", values.get("key2")); assertTrue(values.containsField("key3")); @@ -500,7 +454,9 @@ pojo.setKey5("test5"); MongoStorage storage = makeStorage(); - storage.putPojo(testCategory, true, pojo); + Put replace = storage.createReplace(testCategory); + replace.setPojo(pojo); + replace.apply(); ArgumentCaptor<DBObject> queryCaptor = ArgumentCaptor.forClass(DBObject.class); ArgumentCaptor<DBObject> valueCaptor = ArgumentCaptor.forClass(DBObject.class);
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java Wed Jan 09 14:59:30 2013 -0500 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java Mon Jan 14 14:04:50 2013 -0500 @@ -58,8 +58,8 @@ static final Key<Boolean> THREAD_ALLOCATED_MEMORY_KEY = new Key<Boolean>(THREAD_ALLOCATED_MEMORY, false); static final Key<List<String>> SUPPORTED_FEATURES_LIST_KEY = new Key<List<String>>(SUPPORTED_FEATURES_LIST, false); - static final Category THREAD_CAPABILITIES = - new Category("vm-thread-capabilities", Key.AGENT_ID, Key.VM_ID, + static final Category<VMThreadCapabilities> THREAD_CAPABILITIES = + new Category<>("vm-thread-capabilities", VMThreadCapabilities.class, Key.AGENT_ID, Key.VM_ID, SUPPORTED_FEATURES_LIST_KEY); @@ -71,8 +71,8 @@ static final String DAEMON_THREADS = "currentDaemonThreads"; static final Key<Long> DAEMON_THREADS_KEY = new Key<Long>(DAEMON_THREADS, false); - static final Category THREAD_SUMMARY = - new Category("vm-thread-summary", Key.AGENT_ID, Key.VM_ID, + static final Category<ThreadSummary> THREAD_SUMMARY = + new Category<>("vm-thread-summary", ThreadSummary.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, LIVE_THREADS_KEY, DAEMON_THREADS_KEY); @@ -95,8 +95,8 @@ static final String THREAD_WAIT_COUNT = "threadWaitCount"; static final Key<Long> THREAD_WAIT_COUNT_KEY = new Key<Long>(THREAD_WAIT_COUNT, false); - static final Category THREAD_INFO = - new Category("vm-thread-info", Key.AGENT_ID, Key.VM_ID, + static final Category<ThreadInfoData> THREAD_INFO = + new Category<>("vm-thread-info", ThreadInfoData.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, THREAD_NAME_KEY, THREAD_ID_KEY, THREAD_STATE_KEY, THREAD_CPU_TIME_KEY,
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -43,10 +43,11 @@ import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.core.Query.Criteria; +import com.redhat.thermostat.storage.model.Pojo; import com.redhat.thermostat.thread.dao.ThreadDao; import com.redhat.thermostat.thread.model.ThreadInfoData; import com.redhat.thermostat.thread.model.ThreadSummary; @@ -64,37 +65,36 @@ @Override public VMThreadCapabilities loadCapabilities(VmRef vm) { - try { - Query query = storage.createQuery() - .from(THREAD_CAPABILITIES) - .where(Key.VM_ID, Query.Criteria.EQUALS, vm.getId()) - .where(Key.AGENT_ID, Query.Criteria.EQUALS, vm.getAgent().getAgentId()); - - VMThreadCapabilities caps = storage.findPojo(query, VMThreadCapabilities.class); + Query<VMThreadCapabilities> query = storage.createQuery(THREAD_CAPABILITIES); + query.where(Key.VM_ID, Query.Criteria.EQUALS, vm.getId()); + query.where(Key.AGENT_ID, Query.Criteria.EQUALS, vm.getAgent().getAgentId()); + query.limit(1); + VMThreadCapabilities caps = query.execute().next(); return caps; - } catch (Throwable t) { - t.printStackTrace(); - System.exit(0); - return null; - } } @Override public void saveCapabilities(VMThreadCapabilities caps) { - storage.putPojo(THREAD_CAPABILITIES, true, caps); + Put replace = storage.createReplace(THREAD_CAPABILITIES); + replace.setPojo(caps); + replace.apply(); } @Override public void saveSummary(ThreadSummary summary) { - storage.putPojo(THREAD_SUMMARY, false, summary); + Put add = storage.createAdd(THREAD_SUMMARY); + add.setPojo(summary); + add.apply(); } @Override public ThreadSummary loadLastestSummary(VmRef ref) { ThreadSummary summary = null; - Query query = prepareQuery(THREAD_SUMMARY, ref).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING).limit(1); - Cursor<ThreadSummary> cursor = storage.findAllPojos(query, ThreadSummary.class); + Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ref); + query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + query.limit(1); + Cursor<ThreadSummary> cursor = query.execute(); if (cursor.hasNext()) { summary = cursor.next(); } @@ -107,10 +107,11 @@ List<ThreadSummary> result = new ArrayList<>(); - Query query = prepareQuery(THREAD_SUMMARY, ref).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + Query<ThreadSummary> query = prepareQuery(THREAD_SUMMARY, ref); + query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since); - Cursor<ThreadSummary> cursor = storage.findAllPojos(query, ThreadSummary.class); + Cursor<ThreadSummary> cursor = query.execute(); while (cursor.hasNext()) { ThreadSummary summary = cursor.next(); result.add(summary); @@ -121,18 +122,20 @@ @Override public void saveThreadInfo(ThreadInfoData info) { - storage.putPojo(THREAD_INFO, false, info); + Put add = storage.createAdd(THREAD_INFO); + add.setPojo(info); + add.apply(); } @Override public List<ThreadInfoData> loadThreadInfo(VmRef ref, long since) { List<ThreadInfoData> result = new ArrayList<>(); - Query query = prepareQuery(THREAD_INFO, ref) - .where(Key.TIMESTAMP, Criteria.GREATER_THAN, since) - .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + Query<ThreadInfoData> query = prepareQuery(THREAD_INFO, ref); + query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since); + query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); - Cursor<ThreadInfoData> cursor = storage.findAllPojos(query, ThreadInfoData.class); + Cursor<ThreadInfoData> cursor = query.execute(); while (cursor.hasNext()) { ThreadInfoData info = cursor.next(); result.add(info); @@ -141,15 +144,14 @@ return result; } - private Query prepareQuery(Category category, VmRef vm) { + private <T extends Pojo> Query<T> prepareQuery(Category<T> category, VmRef vm) { return prepareQuery(category, vm.getIdString(), vm.getAgent().getAgentId()); } - private Query prepareQuery(Category category, String vmId, String agentId) { - Query query = storage.createQuery() - .from(category) - .where(Key.AGENT_ID, Query.Criteria.EQUALS, agentId) - .where(Key.VM_ID, Query.Criteria.EQUALS, Integer.valueOf(vmId)); + private <T extends Pojo> Query<T> prepareQuery(Category<T> category, String vmId, String agentId) { + Query<T> query = storage.createQuery(category); + query.where(Key.AGENT_ID, Query.Criteria.EQUALS, agentId); + query.where(Key.VM_ID, Query.Criteria.EQUALS, Integer.valueOf(vmId)); return query; }
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -38,18 +38,23 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import org.junit.Test; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; -import com.redhat.thermostat.test.MockQuery; import com.redhat.thermostat.thread.dao.ThreadDao; import com.redhat.thermostat.thread.model.VMThreadCapabilities; @@ -69,9 +74,9 @@ @Test public void testLoadVMCapabilities() { - MockQuery query = new MockQuery(); + Query query = mock(Query.class); Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(query); + when(storage.createQuery(any(Category.class))).thenReturn(query); VmRef ref = mock(VmRef.class); when(ref.getId()).thenReturn(42); @@ -82,14 +87,20 @@ VMThreadCapabilities expected = new VMThreadCapabilities(); expected.setSupportedFeaturesList(new String[] { ThreadDao.CPU_TIME, ThreadDao.THREAD_ALLOCATED_MEMORY }); - when(storage.findPojo(query, VMThreadCapabilities.class)).thenReturn(expected); + Cursor cursor = mock(Cursor.class); + when(cursor.hasNext()).thenReturn(true).thenReturn(false); + when(cursor.next()).thenReturn(expected).thenReturn(null); + when(query.execute()).thenReturn(cursor); ThreadDaoImpl dao = new ThreadDaoImpl(storage); VMThreadCapabilities caps = dao.loadCapabilities(ref); - assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, 42)); - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, "0xcafe")); - + verify(query).where(Key.VM_ID, Criteria.EQUALS, 42); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "0xcafe"); + verify(query).limit(1); + verify(query).execute(); + verifyNoMoreInteractions(query); + assertFalse(caps.supportContentionMonitor()); assertTrue(caps.supportCPUTime()); assertTrue(caps.supportThreadAllocatedMemory()); @@ -98,7 +109,9 @@ @Test public void testSaveVMCapabilities() { Storage storage = mock(Storage.class); - + Replace replace = mock(Replace.class); + when(storage.createReplace(any(Category.class))).thenReturn(replace); + VMThreadCapabilities caps = mock(VMThreadCapabilities.class); when(caps.supportContentionMonitor()).thenReturn(true); when(caps.supportCPUTime()).thenReturn(true); @@ -107,7 +120,9 @@ ThreadDaoImpl dao = new ThreadDaoImpl(storage); dao.saveCapabilities(caps); - verify(storage).putPojo(ThreadDao.THREAD_CAPABILITIES, true, caps); + verify(storage).createReplace(ThreadDao.THREAD_CAPABILITIES); + verify(replace).setPojo(caps); + verify(replace).apply(); } }
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -47,8 +47,8 @@ static final Key<Long> loadedClassesKey = new Key<>("loadedClasses", false); - static final Category vmClassStatsCategory = new Category( - "vm-class-stats", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, loadedClassesKey); + static final Category<VmClassStat> vmClassStatsCategory = new Category<>( + "vm-class-stats", VmClassStat.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, loadedClassesKey); public List<VmClassStat> getLatestClassStats(VmRef ref, long since);
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -40,6 +40,7 @@ import com.redhat.thermostat.common.dao.VmLatestPojoListGetter; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.VmClassStat; import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO; @@ -52,7 +53,7 @@ VmClassStatDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(vmClassStatsCategory); - this.getter = new VmLatestPojoListGetter<>(storage, vmClassStatsCategory, VmClassStat.class); + this.getter = new VmLatestPojoListGetter<>(storage, vmClassStatsCategory); } @Override @@ -62,6 +63,8 @@ @Override public void putVmClassStat(VmClassStat stat) { - storage.putPojo(vmClassStatsCategory, false, stat); + Put add = storage.createAdd(vmClassStatsCategory); + add.setPojo(stat); + add.apply(); } }
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -39,30 +39,27 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.Collection; import java.util.List; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Add; +import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmClassStat; -import com.redhat.thermostat.test.MockQuery; import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO; -import com.redhat.thermostat.vm.classstat.common.internal.VmClassStatDAOImpl; public class VmClassStatDAOTest { @@ -92,13 +89,9 @@ when(cursor.next()).thenReturn(vmClassStat); Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(VmClassStat.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); HostRef hostRef = mock(HostRef.class); when(hostRef.getAgentId()).thenReturn("system"); @@ -110,9 +103,12 @@ VmClassStatDAO dao = new VmClassStatDAOImpl(storage); List<VmClassStat> vmClassStats = dao.getLatestClassStats(vmRef, Long.MIN_VALUE); - ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class); - verify(storage).findAllPojos(arg.capture(), same(VmClassStat.class)); - assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system"); + verify(query).where(Key.VM_ID, Criteria.EQUALS, 321); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(1, vmClassStats.size()); VmClassStat stat = vmClassStats.get(0); @@ -129,10 +125,15 @@ public void testPutVmClassStat() { Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + VmClassStat stat = new VmClassStat(VM_ID, TIMESTAMP, LOADED_CLASSES); VmClassStatDAO dao = new VmClassStatDAOImpl(storage); dao.putVmClassStat(stat); - verify(storage).putPojo(VmClassStatDAO.vmClassStatsCategory, false, stat); + verify(storage).createAdd(VmClassStatDAO.vmClassStatsCategory); + verify(add).setPojo(stat); + verify(add).apply(); } }
--- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/VmCpuStatDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/VmCpuStatDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -47,7 +47,7 @@ static final Key<Double> vmCpuLoadKey = new Key<>("cpuLoad", false); - static final Category vmCpuStatCategory = new Category("vm-cpu-stats", + static final Category<VmCpuStat> vmCpuStatCategory = new Category<>("vm-cpu-stats", VmCpuStat.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, vmCpuLoadKey); public abstract List<VmCpuStat> getLatestVmCpuStats(VmRef ref, long since);
--- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -40,6 +40,7 @@ import com.redhat.thermostat.common.dao.VmLatestPojoListGetter; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.VmCpuStat; import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; @@ -52,7 +53,7 @@ VmCpuStatDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(vmCpuStatCategory); - this.getter = new VmLatestPojoListGetter<>(storage, vmCpuStatCategory, VmCpuStat.class); + this.getter = new VmLatestPojoListGetter<>(storage, vmCpuStatCategory); } @Override @@ -62,6 +63,8 @@ @Override public void putVmCpuStat(VmCpuStat stat) { - storage.putPojo(vmCpuStatCategory, false, stat); + Put add = storage.createAdd(vmCpuStatCategory); + add.setPojo(stat); + add.apply(); } }
--- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -39,9 +39,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.Collection; @@ -49,19 +49,17 @@ import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Add; +import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmCpuStat; -import com.redhat.thermostat.test.MockQuery; import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class VmCpuStatDAOTest { @@ -97,13 +95,9 @@ when(cursor.next()).thenReturn(cpuStat); Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(VmCpuStat.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); HostRef hostRef = mock(HostRef.class); when(hostRef.getAgentId()).thenReturn("system"); @@ -116,9 +110,13 @@ VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage); List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats(vmRef, Long.MIN_VALUE); - ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class); - verify(storage).findAllPojos(arg.capture(), same(VmCpuStat.class)); - assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(storage).createQuery(VmCpuStatDAO.vmCpuStatCategory); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, vmRef.getAgent().getAgentId()); + verify(query).where(Key.VM_ID, Criteria.EQUALS, vmRef.getId()); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(1, vmCpuStats.size()); VmCpuStat stat = vmCpuStats.get(0); @@ -130,11 +128,16 @@ @Test public void testPutVmCpuStat() { Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + VmCpuStat stat = new VmCpuStat(TIMESTAMP, VM_ID, CPU_LOAD); VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage); dao.putVmCpuStat(stat); - verify(storage).putPojo(VmCpuStatDAO.vmCpuStatCategory, false, stat); + verify(storage).createAdd(VmCpuStatDAO.vmCpuStatCategory); + verify(add).setPojo(stat); + verify(add).apply(); } }
--- a/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/VmGcStatDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/VmGcStatDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -50,7 +50,7 @@ /** time in microseconds */ static final Key<Long> wallTimeKey = new Key<>("wallTime", false); - static final Category vmGcStatCategory = new Category("vm-gc-stats", + static final Category<VmGcStat> vmGcStatCategory = new Category<>("vm-gc-stats", VmGcStat.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, collectorKey, runCountKey, wallTimeKey);
--- a/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -40,6 +40,7 @@ import com.redhat.thermostat.common.dao.VmLatestPojoListGetter; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.VmGcStat; import com.redhat.thermostat.vm.gc.common.VmGcStatDAO; @@ -52,7 +53,7 @@ VmGcStatDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(vmGcStatCategory); - getter = new VmLatestPojoListGetter<>(storage, vmGcStatCategory, VmGcStat.class); + getter = new VmLatestPojoListGetter<>(storage, vmGcStatCategory); } @Override @@ -62,7 +63,9 @@ @Override public void putVmGcStat(VmGcStat stat) { - storage.putPojo(vmGcStatCategory, false, stat); + Put add = storage.createAdd(vmGcStatCategory); + add.setPojo(stat); + add.apply(); } }
--- a/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -39,28 +39,27 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.Collection; import java.util.List; import org.junit.Test; -import org.mockito.ArgumentCaptor; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Add; +import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmGcStat; -import com.redhat.thermostat.test.MockQuery; import com.redhat.thermostat.vm.gc.common.VmGcStatDAO; -import com.redhat.thermostat.vm.gc.common.internal.VmGcStatDAOImpl; public class VmGcStatDAOTest { @@ -94,8 +93,9 @@ when(cursor.next()).thenReturn(vmGcStat); Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(new MockQuery()); - when(storage.findAllPojos(any(Query.class), same(VmGcStat.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); HostRef hostRef = mock(HostRef.class); when(hostRef.getAgentId()).thenReturn("system"); @@ -108,9 +108,14 @@ VmGcStatDAO dao = new VmGcStatDAOImpl(storage); List<VmGcStat> vmGcStats = dao.getLatestVmGcStats(vmRef, Long.MIN_VALUE); - ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class); - verify(storage).findAllPojos(arg.capture(), same(VmGcStat.class)); - assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + verify(storage).createQuery(VmGcStatDAO.vmGcStatCategory); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, "system"); + verify(query).where(Key.VM_ID, Criteria.EQUALS, 321); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + verify(query).execute(); + verifyNoMoreInteractions(query); assertEquals(1, vmGcStats.size()); VmGcStat stat = vmGcStats.get(0); @@ -124,10 +129,15 @@ @Test public void testPutVmGcStat() { Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + VmGcStat stat = new VmGcStat(VM_ID, TIMESTAMP, COLLECTOR, RUN_COUNT, WALL_TIME); VmGcStatDAO dao = new VmGcStatDAOImpl(storage); dao.putVmGcStat(stat); - verify(storage).putPojo(VmGcStatDAO.vmGcStatCategory, false, stat); + verify(storage).createAdd(VmGcStatDAO.vmGcStatCategory); + verify(add).setPojo(stat); + verify(add).apply(); } }
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumperService.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumperService.java Mon Jan 14 14:04:50 2013 -0500 @@ -41,6 +41,7 @@ import com.redhat.thermostat.client.core.controllers.InformationServiceController; import com.redhat.thermostat.client.core.NameMatchingRefFilter; import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.dao.VmInfoDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.utils.OSGIUtils; import com.redhat.thermostat.vm.heap.analysis.client.core.internal.HeapDumpController; @@ -51,12 +52,14 @@ private static final int ORDER = ORDER_MEMORY_GROUP + 60; private ApplicationService appService; + private VmInfoDAO vmInfoDao; private VmMemoryStatDAO vmMemoryStatDao; private HeapDAO heapDao; private Filter<VmRef> filter = new NameMatchingRefFilter<>(); - public HeapDumperService(ApplicationService appService, VmMemoryStatDAO vmMemoryStatDao, HeapDAO heapDao) { + public HeapDumperService(ApplicationService appService, VmInfoDAO vmInfoDao, VmMemoryStatDAO vmMemoryStatDao, HeapDAO heapDao) { + this.vmInfoDao = vmInfoDao; this.vmMemoryStatDao = vmMemoryStatDao; this.heapDao = heapDao; this.appService = appService; @@ -69,7 +72,8 @@ HeapHistogramViewProvider histogramViewProvider = OSGIUtils.getInstance().getService(HeapHistogramViewProvider.class); ObjectDetailsViewProvider objectDetailsViewProvider = OSGIUtils.getInstance().getService(ObjectDetailsViewProvider.class); ObjectRootsViewProvider objectRootsViewProvider = OSGIUtils.getInstance().getService(ObjectRootsViewProvider.class); - return new HeapDumpController(vmMemoryStatDao, heapDao, ref, appService, viewProvider, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider, objectRootsViewProvider); + return new HeapDumpController(vmMemoryStatDao, vmInfoDao, heapDao, ref, appService, + viewProvider, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider, objectRootsViewProvider); } @Override
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapView.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapView.java Mon Jan 14 14:04:50 2013 -0500 @@ -50,9 +50,14 @@ public enum HeapDumperAction { DUMP_REQUESTED, ANALYSE, - REQUEST_ABORTED + REQUEST_ABORTED, } - + + public enum DumpDisabledReason { + DUMP_IN_PROGRESS, + PROCESS_DEAD, + } + protected final ActionNotifier<HeapDumperAction> heapDumperNotifier; protected HeapView() { heapDumperNotifier = new ActionNotifier<HeapDumperAction>(this); @@ -66,18 +71,21 @@ heapDumperNotifier.removeActionListener(listener); } - abstract public void updateUsedAndCapacity(String used, String capacity); + public abstract void updateUsedAndCapacity(String used, String capacity); /** View updates automatically based on the model */ - abstract public void setModel(OverviewChart model); - abstract public void addHeapDump(HeapDump dump); - abstract public void clearHeapDumpList(); - - abstract public void openDumpView(); - abstract public void setChildView(BasicView childView); + public abstract void setModel(OverviewChart model); + + public abstract void enableHeapDumping(); + public abstract void disableHeapDumping(DumpDisabledReason reason); + + public abstract void addHeapDump(HeapDump dump); + public abstract void updateHeapDumpList(List<HeapDump> heapDumps); + public abstract void clearHeapDumpList(); + + public abstract void openDumpView(); + public abstract void setChildView(BasicView childView); public abstract void notifyHeapDumpComplete(); - public abstract void updateHeapDumpList(List<HeapDump> heapDumps); - public abstract void displayWarning(String string); }
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java Mon Jan 14 14:04:50 2013 -0500 @@ -50,6 +50,7 @@ import com.redhat.thermostat.common.Constants; import com.redhat.thermostat.common.MultipleServiceTracker; import com.redhat.thermostat.common.MultipleServiceTracker.Action; +import com.redhat.thermostat.common.dao.VmInfoDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumperService; import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO; @@ -64,6 +65,7 @@ public void start(final BundleContext context) throws Exception { Class<?>[] deps = new Class<?>[] { ApplicationService.class, + VmInfoDAO.class, VmMemoryStatDAO.class, HeapDAO.class, }; @@ -74,12 +76,13 @@ public void dependenciesAvailable(Map<String, Object> services) { ApplicationService appSvc = (ApplicationService) services.get(ApplicationService.class.getName()); Objects.requireNonNull(appSvc); + VmInfoDAO vmInfoDao = Objects.requireNonNull((VmInfoDAO) services.get(VmInfoDAO.class.getName())); VmMemoryStatDAO vmMemoryStatDao = (VmMemoryStatDAO) services.get(VmMemoryStatDAO.class.getName()); Objects.requireNonNull(vmMemoryStatDao); HeapDAO heapDao = (HeapDAO) services.get(HeapDAO.class.getName()); Objects.requireNonNull(heapDao); - HeapDumperService service = new HeapDumperService(appSvc, vmMemoryStatDao, heapDao); + HeapDumperService service = new HeapDumperService(appSvc, vmInfoDao, vmMemoryStatDao, heapDao); Dictionary<String, String> properties = new Hashtable<>(); properties.put(Constants.GENERIC_SERVICE_CLASSNAME, VmRef.class.getName()); reg = context.registerService(InformationService.class.getName(), service , properties);
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java Mon Jan 14 14:04:50 2013 -0500 @@ -54,6 +54,7 @@ import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.Timer.SchedulingType; import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.dao.VmInfoDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.locale.Translate; import com.redhat.thermostat.storage.model.HeapInfo; @@ -63,6 +64,7 @@ import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView; +import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.DumpDisabledReason; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider; import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider; @@ -77,6 +79,7 @@ private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + private final VmInfoDAO vmInfoDao; private final VmMemoryStatDAO vmDao; private final VmRef ref; @@ -92,19 +95,22 @@ private ObjectDetailsViewProvider objectDetailsViewProvider; private ObjectRootsViewProvider objectRootsViewProvider; + public HeapDumpController(final VmMemoryStatDAO vmMemoryStatDao, + final VmInfoDAO vmInfoDao, final HeapDAO heapDao, final VmRef ref, final ApplicationService appService, HeapViewProvider viewProvider, HeapDumpDetailsViewProvider detailsViewProvider, HeapHistogramViewProvider histogramProvider, ObjectDetailsViewProvider objectDetailsProvider, ObjectRootsViewProvider objectRootsProvider) { - this(vmMemoryStatDao, heapDao, ref, appService, viewProvider, + this(vmMemoryStatDao, vmInfoDao, heapDao, ref, appService, viewProvider, detailsViewProvider, histogramProvider, objectDetailsProvider, objectRootsProvider, new HeapDumper(ref)); } HeapDumpController(final VmMemoryStatDAO vmMemoryStatDao, + final VmInfoDAO vmInfoDao, final HeapDAO heapDao, final VmRef ref, final ApplicationService appService, HeapViewProvider viewProvider, HeapDumpDetailsViewProvider detailsViewProvider, @@ -118,6 +124,7 @@ this.detailsViewProvider = detailsViewProvider; this.appService = appService; this.ref = ref; + this.vmInfoDao = vmInfoDao; this.vmDao = vmMemoryStatDao; this.heapDAO = heapDao; @@ -178,6 +185,7 @@ HeapDump dump = null; switch (actionEvent.getActionId()) { case DUMP_REQUESTED: + view.disableHeapDumping(DumpDisabledReason.DUMP_IN_PROGRESS); requestDump(heapDumper); break; case ANALYSE: @@ -189,6 +197,11 @@ } } }); + + boolean vmIsAlive = vmInfoDao.getVmInfo(ref).isAlive(); + if (!vmIsAlive) { + view.disableHeapDumping(DumpDisabledReason.PROCESS_DEAD); + } } private void requestDump(final HeapDumper heapDumper) { @@ -198,6 +211,7 @@ public void run() { try { heapDumper.dump(); + view.enableHeapDumping(); view.notifyHeapDumpComplete(); } catch (CommandException e) { view.displayWarning(e.getMessage());
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java Mon Jan 14 14:04:50 2013 -0500 @@ -68,6 +68,10 @@ HEAP_DUMP_OBJECT_FIND_ROOT, OBJECT_ROOTS_VIEW_TITLE, + + TRIGGER_HEAP_DUMP, + HEAP_DUMP_IN_PROGRESS, + PROCESS_EXITED, ; static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.heap.analysis.client.locale.strings";
--- a/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties Mon Jan 14 14:04:50 2013 -0500 @@ -26,4 +26,8 @@ HEAP_DUMP_OBJECT_BROWSE_REFERENCES = References HEAP_DUMP_OBJECT_FIND_ROOT = Find Root -OBJECT_ROOTS_VIEW_TITLE = Object Roots \ No newline at end of file +OBJECT_ROOTS_VIEW_TITLE = Object Roots + +TRIGGER_HEAP_DUMP = Heap Dump +HEAP_DUMP_IN_PROGRESS = dumping... +PROCESS_EXITED = Process exited.
--- a/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -45,6 +45,7 @@ import com.redhat.thermostat.client.core.InformationService; import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.dao.VmInfoDAO; import com.redhat.thermostat.test.StubBundleContext; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumperService; import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO; @@ -71,10 +72,12 @@ @Test public void verifyActivatorRegistersServices() throws Exception { StubBundleContext context = new StubBundleContext(); + VmInfoDAO vmInfoDao = mock(VmInfoDAO.class); VmMemoryStatDAO vmMemoryStatDAO = mock(VmMemoryStatDAO.class); HeapDAO heapDAO = mock(HeapDAO.class); ApplicationService appSvc = mock(ApplicationService.class); + context.registerService(VmInfoDAO.class, vmInfoDao, null); context.registerService(VmMemoryStatDAO.class, vmMemoryStatDAO, null); context.registerService(HeapDAO.class, heapDAO, null); context.registerService(ApplicationService.class, appSvc, null); @@ -88,7 +91,7 @@ activator.stop(context); assertEquals(0, context.getServiceListeners().size()); - assertEquals(3, context.getAllServices().size()); + assertEquals(4, context.getAllServices().size()); } }
--- a/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -71,8 +71,10 @@ import com.redhat.thermostat.common.TimerFactory; import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.VmInfoDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.storage.model.HeapInfo; +import com.redhat.thermostat.storage.model.VmInfo; import com.redhat.thermostat.storage.model.VmMemoryStat; import com.redhat.thermostat.storage.model.VmMemoryStat.Generation; import com.redhat.thermostat.storage.model.VmMemoryStat.Space; @@ -81,6 +83,7 @@ import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView; +import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.DumpDisabledReason; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider; import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView; @@ -100,6 +103,7 @@ private Timer timer; private HeapDAO heapDao; + private VmInfoDAO vmInfoDao; private VmMemoryStatDAO vmDao; private HeapView view; private HeapDumpDetailsView detailsView; @@ -120,6 +124,10 @@ public void setUp() { heapDao = mock(HeapDAO.class); vmDao = mock(VmMemoryStatDAO.class); + vmInfoDao = mock(VmInfoDAO.class); + VmInfo vmInfo = mock(VmInfo.class); + when(vmInfo.isAlive()).thenReturn(true); + when(vmInfoDao.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo); appService = mock(ApplicationService.class); heapDumper = mock(HeapDumper.class); @@ -184,7 +192,7 @@ when(ref.getIdString()).thenReturn("vm-id"); when(ref.getAgent()).thenReturn(hostRef); - controller = new HeapDumpController(vmDao, heapDao, ref, appService, + controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService, viewProvider, detailsViewProvider, histogramProvider, objectDetailsProvider, objectRootsProvider, heapDumper); } @@ -268,7 +276,7 @@ when(cache.getAttribute(any(VmRef.class))).thenReturn(dump); when(appService.getApplicationCache()).thenReturn(cache); VmRef ref = mock(VmRef.class); - controller = new HeapDumpController(vmDao, heapDao, ref, appService, + controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService, viewProvider, detailsViewProvider, histogramProvider, objectDetailsProvider, objectRootsProvider, heapDumper); @@ -293,7 +301,7 @@ when(appService.getApplicationCache()).thenReturn(cache); VmRef ref = mock(VmRef.class); - controller = new HeapDumpController(vmDao, heapDao, ref, appService, + controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService, viewProvider, detailsViewProvider, histogramProvider, objectDetailsProvider, objectRootsProvider, heapDumper); @@ -301,6 +309,26 @@ } @Test + public void testHeapDumpingDisabledForDeadVms() { + ApplicationCache cache = mock(ApplicationCache.class); + when(appService.getApplicationCache()).thenReturn(cache); + setUpTimers(); + + VmRef ref = mock(VmRef.class); + + VmInfo vmInfo = mock(VmInfo.class); + when(vmInfo.isAlive()).thenReturn(false); + + when(vmInfoDao.getVmInfo(ref)).thenReturn(vmInfo); + + controller = new HeapDumpController(vmDao, vmInfoDao, heapDao, ref, appService, + viewProvider, detailsViewProvider, histogramProvider, + objectDetailsProvider, objectRootsProvider, heapDumper); + + verify(view).disableHeapDumping(DumpDisabledReason.PROCESS_DEAD); + } + + @Test public void testRequestHeapDump() throws CommandException, InterruptedException { final CountDownLatch latch = new CountDownLatch(1); mockExecutorService(latch);
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingView.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingView.java Mon Jan 14 14:04:50 2013 -0500 @@ -77,9 +77,6 @@ stats.addHeapDumperListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - - stats.disableHeapDumperControl(); - heapDumperNotifier.fireAction(HeapDumperAction.DUMP_REQUESTED); } }); @@ -156,6 +153,26 @@ } @Override + public void enableHeapDumping() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + stats.enableHeapDumperControl(); + } + }); + } + + @Override + public void disableHeapDumping(final DumpDisabledReason reason) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + stats.disableHeapDumperControl(reason); + } + }); + } + + @Override public void addHeapDump(final HeapDump dump) { SwingUtilities.invokeLater(new Runnable() { @Override @@ -211,12 +228,7 @@ @Override public void notifyHeapDumpComplete() { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - stats.enableHeapDumperControl(); - } - }); + enableHeapDumping(); } @Override
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/StatsPanel.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/StatsPanel.java Mon Jan 14 14:04:50 2013 -0500 @@ -53,11 +53,16 @@ import javax.swing.SwingConstants; import javax.swing.event.ListSelectionListener; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.DumpDisabledReason; +import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources; import com.redhat.thermostat.vm.heap.analysis.common.HeapDump; @SuppressWarnings("serial") public class StatsPanel extends JPanel { + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + private JPanel leftPanel; private JButton heapDumpButton; @@ -99,7 +104,7 @@ max = new JLabel("-"); max.setHorizontalAlignment(SwingConstants.RIGHT); - heapDumpButton = new JButton("Heap Dump"); + heapDumpButton = new JButton(translator.localize(LocaleResources.TRIGGER_HEAP_DUMP)); heapDumpButton.setName("heapDumpButton"); JScrollPane dumpListScrollPane = new JScrollPane(); @@ -173,13 +178,22 @@ dumpList.addListSelectionListener(listener); } - public void disableHeapDumperControl() { - heapDumpButton.setText("dumping..."); + public void disableHeapDumperControl(DumpDisabledReason reason) { + String text = null; + switch (reason) { + case DUMP_IN_PROGRESS: + text = translator.localize(LocaleResources.HEAP_DUMP_IN_PROGRESS); + break; + case PROCESS_DEAD: + text = translator.localize(LocaleResources.PROCESS_EXITED); + break; + } + heapDumpButton.setText(text); heapDumpButton.setEnabled(false); } public void enableHeapDumperControl() { - heapDumpButton.setText("Heap Dump"); + heapDumpButton.setText(translator.localize(LocaleResources.TRIGGER_HEAP_DUMP)); heapDumpButton.setEnabled(true); }
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -52,7 +52,7 @@ static final Key<String> heapDumpIdKey = new Key<String>("heapDumpId", false); static final Key<String> histogramIdKey = new Key<String>("histogramId", false); - public static final Category heapInfoCategory = new Category("vm-heap-info", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, heapIdKey, heapDumpIdKey, histogramIdKey); + public static final Category<HeapInfo> heapInfoCategory = new Category<>("vm-heap-info", HeapInfo.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, heapIdKey, heapDumpIdKey, histogramIdKey); void putHeapInfo(HeapInfo heapInfo, File heapDumpFile, ObjectHistogram histogramData) throws IOException;
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -53,6 +53,7 @@ import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; @@ -86,7 +87,10 @@ if (histogramData != null) { heapInfo.setHistogramId(histogramId); } - storage.putPojo(heapInfoCategory, false, heapInfo); + Put add = storage.createAdd(heapInfoCategory); + add.setPojo(heapInfo); + add.apply(); + if (heapDumpData != null) { storage.saveFile(heapDumpId, new FileInputStream(heapDumpData)); } @@ -106,11 +110,10 @@ @Override public Collection<HeapInfo> getAllHeapInfo(VmRef vm) { - Query query = storage.createQuery() - .from(heapInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, vm.getAgent().getAgentId()) - .where(Key.VM_ID, Criteria.EQUALS, vm.getId()); - Cursor<HeapInfo> cursor = storage.findAllPojos(query, HeapInfo.class); + Query<HeapInfo> query = storage.createQuery(heapInfoCategory); + query.where(Key.AGENT_ID, Criteria.EQUALS, vm.getAgent().getAgentId()); + query.where(Key.VM_ID, Criteria.EQUALS, vm.getId()); + Cursor<HeapInfo> cursor = query.execute(); Collection<HeapInfo> heapInfos = new ArrayList<>(); while (cursor.hasNext()) { heapInfos.add(cursor.next()); @@ -137,12 +140,12 @@ @Override public HeapInfo getHeapInfo(String heapId) { - Query query = storage.createQuery() - .from(heapInfoCategory) - .where(heapIdKey, Criteria.EQUALS, heapId); + Query<HeapInfo> query = storage.createQuery(heapInfoCategory); + query.where(heapIdKey, Criteria.EQUALS, heapId); + query.limit(1); HeapInfo found = null; try { - found = storage.findPojo(query, HeapInfo.class); + found = query.execute().next(); } catch (IllegalArgumentException iae) { /* * if the heap id is not found, we get a nice
--- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,7 +42,6 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -61,19 +60,16 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.model.HeapInfo; -import com.redhat.thermostat.test.MockQuery; import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO; import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord; import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram; @@ -85,21 +81,23 @@ private HeapDAO dao; private Storage storage; + private Add add; private HeapInfo heapInfo; private File heapDumpData; private ObjectHistogram histogram; private InputStream histogramData; + private Query query; + @Before public void setUp() throws IOException { storage = mock(Storage.class); + add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + when(storage.getAgentId()).thenReturn("test"); - when(storage.createQuery()).then(new Answer<Query>() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); + query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); dao = new HeapDAOImpl(storage); @@ -111,12 +109,6 @@ out.close(); histogramData = createHistogramData(); - // Setup for reading data from DB. - MockQuery findAllQuery = new MockQuery() - .from(HeapDAO.heapInfoCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, "123") - .where(Key.VM_ID, Criteria.EQUALS, 234); - @SuppressWarnings("unchecked") Cursor<HeapInfo> cursor = mock(Cursor.class); HeapInfo info1 = new HeapInfo(234, 12345L); @@ -131,7 +123,7 @@ when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); when(cursor.next()).thenReturn(info1).thenReturn(info2).thenReturn(null); - when(storage.findAllPojos(findAllQuery, HeapInfo.class)).thenReturn(cursor); + when(query.execute()).thenReturn(cursor); // Setup for reading heapdump data. when(storage.loadFile("test-heap")).thenReturn(new ByteArrayInputStream(data)); @@ -170,6 +162,7 @@ @After public void tearDown() { + query = null; histogramData = null; histogram = null; heapDumpData.delete(); @@ -177,6 +170,7 @@ heapInfo = null; dao = null; storage = null; + add = null; } @Test @@ -198,7 +192,9 @@ public void testPutHeapInfo() throws IOException { dao.putHeapInfo(heapInfo, heapDumpData, histogram); - verify(storage).putPojo(HeapDAO.heapInfoCategory, false, heapInfo); + verify(storage).createAdd(HeapDAO.heapInfoCategory); + verify(add).setPojo(heapInfo); + verify(add).apply(); ArgumentCaptor<InputStream> data = ArgumentCaptor.forClass(InputStream.class); verify(storage).saveFile(eq("heapdump-test-123-12345"), data.capture()); @@ -224,7 +220,9 @@ public void testPutHeapInfoWithoutDump() throws IOException { dao.putHeapInfo(heapInfo, null, null); - verify(storage).putPojo(HeapDAO.heapInfoCategory, false, heapInfo); + verify(storage).createAdd(HeapDAO.heapInfoCategory); + verify(add).setPojo(heapInfo); + verify(add).apply(); verify(storage, never()).saveFile(anyString(), any(InputStream.class)); assertEquals("test-123-12345", heapInfo.getHeapId()); @@ -276,9 +274,7 @@ @Test public void testInvalidHeapId() throws IOException { - storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(new MockQuery()); - when(storage.findPojo(any(Query.class), same(HeapInfo.class))).thenThrow(new IllegalArgumentException("invalid ObjectId")); + when(query.execute()).thenThrow(new IllegalArgumentException("invalid ObjectId")); dao = new HeapDAOImpl(storage); heapInfo = dao.getHeapInfo("some-random-heap-id"); assertTrue(heapInfo == null);
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/VmMemoryStatDAO.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/VmMemoryStatDAO.java Mon Jan 14 14:04:50 2013 -0500 @@ -48,7 +48,7 @@ static final Key<Generation[]> generationsKey = new Key<>("generations", false); - static final Category vmMemoryStatsCategory = new Category("vm-memory-stats", + static final Category<VmMemoryStat> vmMemoryStatsCategory = new Category<>("vm-memory-stats", VmMemoryStat.class, Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, generationsKey); public VmMemoryStat getLatestMemoryStat(VmRef ref);
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,9 +42,10 @@ import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmMemoryStat; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; @@ -56,18 +57,17 @@ VmMemoryStatDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(vmMemoryStatsCategory); - getter = new VmLatestPojoListGetter<>(storage, vmMemoryStatsCategory, VmMemoryStat.class); + getter = new VmLatestPojoListGetter<>(storage, vmMemoryStatsCategory); } @Override public VmMemoryStat getLatestMemoryStat(VmRef ref) { - Query query = storage.createQuery() - .from(vmMemoryStatsCategory) - .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId()) - .where(Key.VM_ID, Criteria.EQUALS, ref.getId()) - .sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING) - .limit(1); - Cursor<VmMemoryStat> cursor = storage.findAllPojos(query, VmMemoryStat.class); + Query<VmMemoryStat> query = storage.createQuery(vmMemoryStatsCategory); + query.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgent().getAgentId()); + query.where(Key.VM_ID, Criteria.EQUALS, ref.getId()); + query.sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); + query.limit(1); + Cursor<VmMemoryStat> cursor = query.execute(); if (cursor.hasNext()) { return cursor.next(); } @@ -76,7 +76,9 @@ @Override public void putVmMemoryStat(VmMemoryStat stat) { - storage.putPojo(vmMemoryStatsCategory, false, stat); + Put add = storage.createAdd(vmMemoryStatsCategory); + add.setPojo(stat); + add.apply(); } @Override
--- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -39,9 +39,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.util.ArrayList; @@ -54,17 +54,17 @@ import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Add; +import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.VmMemoryStat; import com.redhat.thermostat.storage.model.VmMemoryStat.Generation; import com.redhat.thermostat.storage.model.VmMemoryStat.Space; -import com.redhat.thermostat.test.MockQuery; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; -import com.redhat.thermostat.vm.memory.common.internal.VmMemoryStatDAOImpl; public class VmMemoryStatDAOTest { @@ -74,7 +74,7 @@ private Storage storage; private VmRef vmRef; - private MockQuery query; + private Query query; private Cursor<VmMemoryStat> cursor; @SuppressWarnings("unchecked") @@ -90,11 +90,11 @@ when(vmRef.getId()).thenReturn(VM_ID); storage = mock(Storage.class); - query = new MockQuery(); - when(storage.createQuery()).thenReturn(query); + query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); cursor = mock(Cursor.class); - when(storage.findAllPojos(any(Query.class), same(VmMemoryStat.class))).thenReturn(cursor); + when(query.execute()).thenReturn(cursor); when(cursor.hasNext()).thenReturn(false); @@ -136,14 +136,16 @@ verifyQuery(); - assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l)); + verify(query).where(Key.TIMESTAMP, Criteria.GREATER_THAN, 123l); + verify(query).execute(); + verifyNoMoreInteractions(query); } private void verifyQuery() { - assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID)); - assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_ID)); - assertTrue(query.hasSort(Key.TIMESTAMP, Query.SortDirection.DESCENDING)); + verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID); + verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_ID); + verify(query).sort(Key.TIMESTAMP, Query.SortDirection.DESCENDING); } @Test @@ -152,8 +154,9 @@ when(cursor.next()).thenReturn(null); Storage storage = mock(Storage.class); - when(storage.createQuery()).thenReturn(new MockQuery()); - when(storage.findAllPojos(any(Query.class), same(VmMemoryStat.class))).thenReturn(cursor); + Query query = mock(Query.class); + when(storage.createQuery(any(Category.class))).thenReturn(query); + when(query.execute()).thenReturn(cursor); VmMemoryStatDAO impl = new VmMemoryStatDAOImpl(storage); VmMemoryStat latest = impl.getLatestMemoryStat(vmRef); @@ -194,9 +197,14 @@ VmMemoryStat stat = new VmMemoryStat(1, 2, generations.toArray(new Generation[generations.size()])); Storage storage = mock(Storage.class); + Add add = mock(Add.class); + when(storage.createAdd(any(Category.class))).thenReturn(add); + VmMemoryStatDAO dao = new VmMemoryStatDAOImpl(storage); dao.putVmMemoryStat(stat); - verify(storage).putPojo(VmMemoryStatDAO.vmMemoryStatsCategory, false, stat); + verify(storage).createAdd(VmMemoryStatDAO.vmMemoryStatsCategory); + verify(add).setPojo(stat); + verify(add).apply(); } }
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java Mon Jan 14 14:04:50 2013 -0500 @@ -43,6 +43,7 @@ import java.io.OutputStream; import java.io.Reader; import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.security.SecureRandom; @@ -57,6 +58,7 @@ import javax.net.ssl.SSLContext; +import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.codec.binary.Base64; import org.apache.http.Header; import org.apache.http.HttpEntity; @@ -84,17 +86,20 @@ import com.redhat.thermostat.common.ssl.SslInitException; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.config.StartupConfiguration; +import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.AuthToken; +import com.redhat.thermostat.storage.core.BasePut; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Connection; import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Remove; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.SecureStorage; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.StorageException; import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.model.AgentIdPojo; import com.redhat.thermostat.storage.model.Pojo; import com.redhat.thermostat.web.common.ThermostatGSONConverter; import com.redhat.thermostat.web.common.WebInsert; @@ -271,10 +276,53 @@ } + private class WebAdd extends BasePut implements Add { + + @Override + public void apply() { + int categoryId = getCategoryId(getCategory()); + putImpl(new WebInsert(categoryId, false), getPojo()); + } + + } + + private class WebReplace extends BasePut implements Replace { + + @Override + public void apply() { + int categoryId = getCategoryId(getCategory()); + putImpl(new WebInsert(categoryId, true), getPojo()); + } + + } + + private class WebUpdateImpl extends WebUpdate implements Update { + + @Override + public void apply() { + updatePojo(this); + } + } + + private class WebQueryImpl<T extends Pojo> extends WebQuery<T> { + + private transient Class<T> dataClass; + + WebQueryImpl(int categoryId, Class<T> dataClass) { + super(categoryId); + this.dataClass = dataClass; + } + + @Override + public Cursor<T> execute() { + return findAllPojos(this, dataClass); + } + } + private String endpoint; private UUID agentId; - private Map<Category, Integer> categoryIds; + private Map<Category<?>, Integer> categoryIds; private Gson gson; // package private for testing DefaultHttpClient httpClient; @@ -384,7 +432,7 @@ } @Override - public void registerCategory(Category category) throws StorageException { + public void registerCategory(Category<?> category) throws StorageException { NameValuePair nameParam = new BasicNameValuePair("name", category.getName()); NameValuePair categoryParam = new BasicNameValuePair("category", @@ -400,8 +448,8 @@ } @Override - public Query createQuery() { - return new WebQuery(categoryIds); + public <T extends Pojo> Query<T> createQuery(Category<T> category) { + return new WebQueryImpl<>(categoryIds.get(category), category.getDataClass()); } @Override @@ -410,43 +458,24 @@ } @Override - public WebUpdate createUpdate() { - return new WebUpdate(categoryIds); + public Update createUpdate(Category<?> category) { + WebUpdateImpl updateImpl = new WebUpdateImpl(); + updateImpl.setCategoryId(categoryIds.get(category)); + return updateImpl; } @SuppressWarnings("unchecked") - @Override - public <T extends Pojo> Cursor<T> findAllPojos(Query query, - Class<T> resultClass) throws StorageException { - ((WebQuery) query).setResultClassName(resultClass.getName()); - NameValuePair queryParam = new BasicNameValuePair("query", - gson.toJson(query)); + private <T extends Pojo> Cursor<T> findAllPojos(WebQuery<T> query, Class<T> resultClass) throws StorageException { + NameValuePair queryParam = new BasicNameValuePair("query", gson.toJson(query)); List<NameValuePair> formparams = Arrays.asList(queryParam); - try (CloseableHttpEntity entity = post(endpoint + "/find-all", - formparams)) { + try (CloseableHttpEntity entity = post(endpoint + "/find-all", formparams)) { Reader reader = getContentAsReader(entity); - T[] result = (T[]) gson.fromJson(reader, - Array.newInstance(resultClass, 0).getClass()); + T[] result = (T[]) gson.fromJson(reader, Array.newInstance(resultClass, 0).getClass()); return new WebCursor<T>(result); } } @Override - public <T extends Pojo> T findPojo(Query query, Class<T> resultClass) - throws StorageException { - ((WebQuery) query).setResultClassName(resultClass.getName()); - NameValuePair queryParam = new BasicNameValuePair("query", - gson.toJson(query)); - List<NameValuePair> formparams = Arrays.asList(queryParam); - try (CloseableHttpEntity entity = post(endpoint + "/find-pojo", - formparams)) { - Reader reader = getContentAsReader(entity); - T result = gson.fromJson(reader, resultClass); - return result; - } - } - - @Override public String getAgentId() { return agentId.toString(); } @@ -457,12 +486,10 @@ } @Override - public long getCount(Category category) throws StorageException { - NameValuePair categoryParam = new BasicNameValuePair("category", - gson.toJson(categoryIds.get(category))); + public long getCount(Category<?> category) throws StorageException { + NameValuePair categoryParam = new BasicNameValuePair("category", gson.toJson(categoryIds.get(category))); List<NameValuePair> formparams = Arrays.asList(categoryParam); - try (CloseableHttpEntity entity = post(endpoint + "/get-count", - formparams)) { + try (CloseableHttpEntity entity = post(endpoint + "/get-count", formparams)) { Reader reader = getContentAsReader(entity); long result = gson.fromJson(reader, Long.class); return result; @@ -483,18 +510,22 @@ } @Override - public void putPojo(final Category category, final boolean replace, final AgentIdPojo pojo) - throws StorageException { + public Add createAdd(Category<?> into) { + WebAdd add = new WebAdd(); + add.setCategory(into); + return add; + } - // TODO: This logic should probably be moved elsewhere. I.e. out of the - // Storage API. - if (pojo.getAgentId() == null) { - pojo.setAgentId(getAgentId()); - } + @Override + public Replace createReplace(Category<?> into) { + WebReplace replace = new WebReplace(); + replace.setCategory(into); + return replace; + } - int categoryId = categoryIds.get(category); - WebInsert insert = new WebInsert(categoryId, replace, pojo.getClass() - .getName()); + private void putImpl(WebInsert insert, final Pojo pojo) throws StorageException { + + maybeAddAgentId(pojo); NameValuePair insertParam = new BasicNameValuePair("insert", gson.toJson(insert)); NameValuePair pojoParam = new BasicNameValuePair("pojo", @@ -504,6 +535,16 @@ } + private void maybeAddAgentId(final Pojo pojo) throws AssertionError { + try { + if (BeanUtils.getProperty(pojo, Key.AGENT_ID.getName()) == null) { + BeanUtils.setProperty(pojo, Key.AGENT_ID.getName(), getAgentId()); + } + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError("Pojo needs to have an agentId property"); + } + } + @Override public void removePojo(Remove remove) throws StorageException { NameValuePair removeParam = new BasicNameValuePair("remove", @@ -525,8 +566,7 @@ this.agentId = agentId; } - @Override - public void updatePojo(Update update) throws StorageException { + private void updatePojo(Update update) throws StorageException { WebUpdate webUp = (WebUpdate) update; List<WebUpdate.UpdateValue> updateValues = webUp.getUpdates(); List<Object> values = new ArrayList<>(updateValues.size()); @@ -599,4 +639,8 @@ // Nothing to do here. } + int getCategoryId(Category<?> category) { + return categoryIds.get(category); + } + }
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -86,9 +86,11 @@ import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Remove; +import com.redhat.thermostat.storage.core.Update; import com.redhat.thermostat.test.FreePortFinder; import com.redhat.thermostat.test.FreePortFinder.TryPort; import com.redhat.thermostat.web.common.Qualifier; @@ -111,7 +113,7 @@ private String requestURI; private int responseStatus; - private static Category category; + private static Category<TestObj> category; private static Key<String> key1; private static Key<Integer> key2; @@ -121,7 +123,7 @@ public static void setupCategory() { key1 = new Key<>("property1", true); key2 = new Key<>("property2", true); - category = new Category("test", key1); + category = new Category<>("test", TestObj.class, key1); } @AfterClass @@ -219,35 +221,6 @@ } @Test - public void testFindPojo() throws UnsupportedEncodingException, IOException { - - TestObj obj = new TestObj(); - obj.setProperty1("fluffor"); - Gson gson = new Gson(); - responseBody = gson.toJson(obj); - - Query query = storage.createQuery().from(category).where(key1, Criteria.EQUALS, "fluff"); - - TestObj result = storage.findPojo(query, TestObj.class); - StringReader reader = new StringReader(requestBody); - BufferedReader bufRead = new BufferedReader(reader); - String line = URLDecoder.decode(bufRead.readLine(), "UTF-8"); - String[] parts = line.split("="); - assertEquals("query", parts[0]); - WebQuery restQuery = gson.fromJson(parts[1], WebQuery.class); - - assertEquals(42, restQuery.getCategoryId()); - List<Qualifier<?>> qualifiers = restQuery.getQualifiers(); - assertEquals(1, qualifiers.size()); - Qualifier<?> qual = qualifiers.get(0); - assertEquals(new Key<String>("property1", true), qual.getKey()); - assertEquals(Criteria.EQUALS, qual.getCriteria()); - assertEquals("fluff", qual.getValue()); - - assertEquals("fluffor", result.getProperty1()); - } - - @Test public void testFindAllPojos() throws UnsupportedEncodingException, IOException { TestObj obj1 = new TestObj(); @@ -258,15 +231,16 @@ responseBody = gson.toJson(Arrays.asList(obj1, obj2)); Key<String> key1 = new Key<>("property1", true); - Query query = storage.createQuery().from(category).where(key1, Criteria.EQUALS, "fluff"); + Query<TestObj> query = storage.createQuery(category); + query.where(key1, Criteria.EQUALS, "fluff"); - Cursor<TestObj> results = storage.findAllPojos(query, TestObj.class); + Cursor<TestObj> results = query.execute(); StringReader reader = new StringReader(requestBody); BufferedReader bufRead = new BufferedReader(reader); String line = URLDecoder.decode(bufRead.readLine(), "UTF-8"); String[] parts = line.split("="); assertEquals("query", parts[0]); - WebQuery restQuery = gson.fromJson(parts[1], WebQuery.class); + WebQuery<?> restQuery = gson.fromJson(parts[1], WebQuery.class); assertEquals(42, restQuery.getCategoryId()); List<Qualifier<?>> qualifiers = restQuery.getQualifiers(); @@ -289,7 +263,13 @@ TestObj obj = new TestObj(); obj.setProperty1("fluff"); - storage.putPojo(category, true, obj); + // We need an agentId, so that we can check automatic insert of agentId. + UUID agentId = new UUID(1, 2); + storage.setAgentId(agentId); + + Put replace = storage.createReplace(category); + replace.setPojo(obj); + replace.apply(); Gson gson = new Gson(); StringReader reader = new StringReader(requestBody); @@ -302,12 +282,14 @@ WebInsert insert = gson.fromJson(parts[1], WebInsert.class); assertEquals(42, insert.getCategoryId()); assertEquals(true, insert.isReplace()); - assertEquals(TestObj.class.getName(), insert.getPojoClass()); parts = params[1].split("="); assertEquals(2, parts.length); assertEquals("pojo", parts[0]); - Object resultObj = gson.fromJson(parts[1], Class.forName(insert.getPojoClass())); + Object resultObj = gson.fromJson(parts[1], TestObj.class); + + // Set agentId on expected object, because we expect WebStorage to insert it for us. + obj.setAgentId(agentId.toString()); assertEquals(obj, resultObj); } @@ -352,21 +334,19 @@ @Test public void testCreateUpdate() { - WebUpdate update = (WebUpdate) storage.createUpdate(); + WebUpdate update = (WebUpdate) storage.createUpdate(category); assertNotNull(update); - update = update.from(category); assertEquals(42, update.getCategoryId()); - assertNotNull(update); - update = update.where(key1, "test"); - assertNotNull(update); + + update.where(key1, "test"); List<Qualifier<?>> qualifiers = update.getQualifiers(); assertEquals(1, qualifiers.size()); Qualifier<?> qualifier = qualifiers.get(0); assertEquals(key1, qualifier.getKey()); assertEquals(Criteria.EQUALS, qualifier.getCriteria()); assertEquals("test", qualifier.getValue()); - update = update.set(key1, "fluff"); - assertNotNull(update); + + update.set(key1, "fluff"); List<WebUpdate.UpdateValue> updates = update.getUpdates(); assertEquals(1, updates.size()); assertEquals("fluff", updates.get(0).getValue()); @@ -377,8 +357,11 @@ @Test public void testUpdate() throws UnsupportedEncodingException, IOException, JsonSyntaxException, ClassNotFoundException { - WebUpdate update = storage.createUpdate().from(category).where(key1, "test").set(key1, "fluff").set(key2, 42); - storage.updatePojo(update); + Update update = storage.createUpdate(category); + update.where(key1, "test"); + update.set(key1, "fluff"); + update.set(key2, 42); + update.apply(); Gson gson = new Gson(); StringReader reader = new StringReader(requestBody);
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebInsert.java Mon Jan 14 14:04:50 2013 -0500 @@ -42,16 +42,13 @@ private int categoryId; private boolean replace; - private String pojoClass; public WebInsert() { - this(-1, false, null); } - public WebInsert(int categoryId, boolean replace, String pojoClass) { + public WebInsert(int categoryId, boolean replace) { this.categoryId = categoryId; this.replace = replace; - this.pojoClass = pojoClass; } public int getCategoryId() { @@ -62,14 +59,6 @@ this.categoryId = categoryId; } - public String getPojoClass() { - return pojoClass; - } - - public void setPojoClass(String pojoClass) { - this.pojoClass = pojoClass; - } - public boolean isReplace() { return replace; }
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebQuery.java Mon Jan 14 14:04:50 2013 -0500 @@ -39,35 +39,25 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; import com.redhat.thermostat.storage.core.AbstractQuery; -import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.model.Pojo; -public class WebQuery extends AbstractQuery { +public class WebQuery<T extends Pojo> extends AbstractQuery<T> { private List<Qualifier<?>> qualifiers; - private String resultClassName; - - private transient Map<Category, Integer> categoryIdMap; private int categoryId; public WebQuery() { - this(null); + this(-1); } - public WebQuery(Map<Category, Integer> categoryIdMap) { + public WebQuery(int categoryId) { qualifiers = new ArrayList<>(); - this.categoryIdMap = categoryIdMap; - } - - @Override - public WebQuery from(Category category) { - categoryId = categoryIdMap.get(category); - return this; + this.categoryId = categoryId; } public int getCategoryId() { @@ -79,9 +69,8 @@ } @Override - public <T> WebQuery where(Key<T> key, Criteria criteria, T value) { + public <S> void where(Key<S> key, Criteria criteria, S value) { qualifiers.add(new Qualifier<>(key, criteria, value)); - return this; } public List<Qualifier<?>> getQualifiers() { @@ -92,12 +81,10 @@ this.qualifiers = qualifiers; } - public String getResultClassName() { - return resultClassName; - } - - public void setResultClassName(String resultClassName) { - this.resultClassName = resultClassName; + @Override + public Cursor<T> execute() { + // This should only ever be called when created from WebStorage, which provides its own subclass. + throw new IllegalStateException(); } }
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java Mon Jan 14 14:04:50 2013 -0500 @@ -47,7 +47,7 @@ public class WebRemove implements Remove { - private transient Map<Category, Integer> categoryIds; + private transient Map<Category<?>, Integer> categoryIds; private int categoryId; private List<Qualifier<?>> qualifiers; @@ -56,7 +56,7 @@ this(null); } - public WebRemove(Map<Category, Integer> categoryIds) { + public WebRemove(Map<Category<?>, Integer> categoryIds) { qualifiers = new ArrayList<>(); this.categoryIds = categoryIds; }
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java Mon Jan 14 14:04:50 2013 -0500 @@ -38,14 +38,11 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; -import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.Update; import com.redhat.thermostat.storage.core.Query.Criteria; -public class WebUpdate implements Update { +public class WebUpdate { public static class UpdateValue { private Key<?> key; @@ -90,44 +87,31 @@ } - private transient Map<Category, Integer> categoryIds; - private Integer categoryId; + private int categoryId; private List<Qualifier<?>> qualifiers; private List<UpdateValue> updateValues; - // NOTE: This is needed for de-serialization! public WebUpdate() { - this(null); - } - - public WebUpdate(Map<Category, Integer> categoryIds) { qualifiers = new ArrayList<>(); updateValues = new ArrayList<>(); - this.categoryIds = categoryIds; } - @Override - public WebUpdate from(Category category) { - categoryId = categoryIds.get(category); - return this; + public <T> void where(Key<T> key, T value) { + qualifiers.add(new Qualifier<T>(key, Criteria.EQUALS, value)); } - @Override - public <T> WebUpdate where(Key<T> key, T value) { - qualifiers.add(new Qualifier<T>(key, Criteria.EQUALS, value)); - return this; - } - - @Override - public <T> WebUpdate set(Key<T> key, T value) { + public <T> void set(Key<T> key, T value) { updateValues.add(new UpdateValue(key, value)); - return this; } public int getCategoryId() { return categoryId; } + public void setCategoryId(int categoryId) { + this.categoryId = categoryId; + } + public List<Qualifier<?>> getQualifiers() { return qualifiers; }
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -36,7 +36,6 @@ package com.redhat.thermostat.web.common; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; import java.util.HashMap; import java.util.List; @@ -47,19 +46,22 @@ import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query.Criteria; -import com.redhat.thermostat.web.common.Qualifier; -import com.redhat.thermostat.web.common.WebQuery; +import com.redhat.thermostat.storage.model.Pojo; public class WebQueryTest { + private static class TestObj implements Pojo { + + } + @Test public void test() { Key<String> key1 = new Key<>("testkey", true); - Category category = new Category("test", key1); + Category<TestObj> category = new Category<>("test", TestObj.class, key1); Map<Category,Integer> categoryIdMap = new HashMap<>(); categoryIdMap.put(category, 42); - WebQuery query = new WebQuery(categoryIdMap); - query.from(category).where(key1, Criteria.EQUALS, "fluff"); + WebQuery query = new WebQuery(42); + query.where(key1, Criteria.EQUALS, "fluff"); List<Qualifier<?>> qualifiers = query.getQualifiers(); assertEquals(1, qualifiers.size());
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Mon Jan 14 14:04:50 2013 -0500 @@ -65,12 +65,12 @@ import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Put; import com.redhat.thermostat.storage.core.Query; import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Remove; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; -import com.redhat.thermostat.storage.model.AgentIdPojo; import com.redhat.thermostat.storage.model.Pojo; import com.redhat.thermostat.web.common.Qualifier; import com.redhat.thermostat.web.common.StorageWrapper; @@ -100,7 +100,7 @@ private int currentCategoryId; private Map<String, Integer> categoryIds; - private Map<Integer, Category> categories; + private Map<Integer, Category<?>> categories; public void init() { gson = new GsonBuilder().registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()).create(); @@ -126,9 +126,7 @@ String uri = req.getRequestURI(); int lastPartIdx = uri.lastIndexOf("/"); String cmd = uri.substring(lastPartIdx + 1); - if (cmd.equals("find-pojo")) { - findPojo(req, resp); - } else if (cmd.equals("find-all")) { + if (cmd.equals("find-all")) { findAll(req, resp); } else if (cmd.equals("put-pojo")) { putPojo(req, resp); @@ -207,7 +205,7 @@ try { String categoryParam = req.getParameter("category"); int categoryId = gson.fromJson(categoryParam, Integer.class); - Category category = categories.get(categoryId); + Category<?> category = getCategoryFromId(categoryId); long result = storage.getCount(category); resp.setStatus(HttpServletResponse.SC_OK); resp.setContentType("application/json"); @@ -226,8 +224,8 @@ if (categoryIds.containsKey(categoryName)) { id = categoryIds.get(categoryName); } else { - // The following has the side effect of registering the newly deserialized Category in the Categories clas. - Category category = gson.fromJson(categoryParam, Category.class); + // The following has the side effect of registering the newly deserialized Category in the Categories class. + Category<?> category = gson.fromJson(categoryParam, Category.class); storage.registerCategory(category); id = currentCategoryId; @@ -247,19 +245,18 @@ resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; } - try { - String insertParam = req.getParameter("insert"); - WebInsert insert = gson.fromJson(insertParam, WebInsert.class); - Class<? extends AgentIdPojo> pojoCls = (Class<? extends AgentIdPojo>) Class.forName(insert.getPojoClass()); - String pojoParam = req.getParameter("pojo"); - AgentIdPojo pojo = gson.fromJson(pojoParam, pojoCls); - int categoryId = insert.getCategoryId(); - Category category = getCategoryFromId(categoryId); - storage.putPojo(category, insert.isReplace(), pojo); - resp.setStatus(HttpServletResponse.SC_OK); - } catch (ClassNotFoundException ex) { - resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } + + String insertParam = req.getParameter("insert"); + WebInsert insert = gson.fromJson(insertParam, WebInsert.class); + int categoryId = insert.getCategoryId(); + Category<?> category = getCategoryFromId(categoryId); + Class<? extends Pojo> pojoCls = category.getDataClass(); + String pojoParam = req.getParameter("pojo"); + Pojo pojo = gson.fromJson(pojoParam, pojoCls); + Put targetPut = insert.isReplace() ? storage.createReplace(category) : storage.createAdd(category); + targetPut.setPojo(pojo); + targetPut.apply(); + resp.setStatus(HttpServletResponse.SC_OK); } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -282,12 +279,11 @@ try { String updateParam = req.getParameter("update"); WebUpdate update = gson.fromJson(updateParam, WebUpdate.class); - Update targetUpdate = storage.createUpdate(); - targetUpdate = targetUpdate.from(getCategoryFromId(update.getCategoryId())); + Update targetUpdate = storage.createUpdate(getCategoryFromId(update.getCategoryId())); List<Qualifier<?>> qualifiers = update.getQualifiers(); for (Qualifier qualifier : qualifiers) { assert (qualifier.getCriteria() == Criteria.EQUALS); - targetUpdate = targetUpdate.where(qualifier.getKey(), qualifier.getValue()); + targetUpdate.where(qualifier.getKey(), qualifier.getValue()); } List<WebUpdate.UpdateValue> updates = update.getUpdates(); if (updates != null) { @@ -306,7 +302,7 @@ targetUpdate.set(key, value); } } - storage.updatePojo(targetUpdate); + targetUpdate.apply(); resp.setStatus(HttpServletResponse.SC_OK); } catch (ClassNotFoundException ex) { ex.printStackTrace(); @@ -315,57 +311,36 @@ } @SuppressWarnings({ "rawtypes", "unchecked" }) - private void findPojo(HttpServletRequest req, HttpServletResponse resp) throws IOException { - try { - String queryParam = req.getParameter("query"); - WebQuery query = gson.fromJson(queryParam, WebQuery.class); - Class resultClass = Class.forName(query.getResultClassName()); - Query targetQuery = constructTargetQuery(query); - Object result = storage.findPojo(targetQuery, resultClass); - writeResponse(resp, result); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "result class not found"); + private void findAll(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String queryParam = req.getParameter("query"); + WebQuery query = gson.fromJson(queryParam, WebQuery.class); + Query targetQuery = constructTargetQuery(query); + ArrayList resultList = new ArrayList(); + Cursor result = targetQuery.execute(); + while (result.hasNext()) { + resultList.add(result.next()); } + writeResponse(resp, resultList.toArray()); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - private void findAll(HttpServletRequest req, HttpServletResponse resp) throws IOException { - try { - String queryParam = req.getParameter("query"); - WebQuery query = gson.fromJson(queryParam, WebQuery.class); - Class resultClass = Class.forName(query.getResultClassName()); - Query targetQuery = constructTargetQuery(query); - ArrayList resultList = new ArrayList(); - Cursor result = storage.findAllPojos(targetQuery, resultClass); - while (result.hasNext()) { - resultList.add(result.next()); - } - writeResponse(resp, resultList.toArray()); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "result class not found"); - } - } + private Query<?> constructTargetQuery(WebQuery<? extends Pojo> query) { + int categoryId = query.getCategoryId(); + Category<?> category = getCategoryFromId(categoryId); - private Query constructTargetQuery(WebQuery query) { - Query targetQuery = storage.createQuery(); - int categoryId = query.getCategoryId(); - Category category = getCategoryFromId(categoryId); - targetQuery = targetQuery.from(category); + Query<?> targetQuery = storage.createQuery(category); List<Qualifier<?>> qualifiers = query.getQualifiers(); for (Qualifier q : qualifiers) { - targetQuery = targetQuery.where(q.getKey(), q.getCriteria(), q.getValue()); + targetQuery.where(q.getKey(), q.getCriteria(), q.getValue()); } for (Sort s : query.getSorts()) { - targetQuery = targetQuery.sort(s.getKey(), s.getDirection()); + targetQuery.sort(s.getKey(), s.getDirection()); } - targetQuery = targetQuery.limit(query.getLimit()); + targetQuery.limit(query.getLimit()); return targetQuery; } - private Category getCategoryFromId(int categoryId) { - Category category = categories.get(categoryId); + private Category<?> getCategoryFromId(int categoryId) { + Category<?> category = categories.get(categoryId); return category; }
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/QueryTestHelper.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/QueryTestHelper.java Mon Jan 14 14:04:50 2013 -0500 @@ -44,20 +44,10 @@ import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Remove; -import com.redhat.thermostat.storage.core.Update; public class QueryTestHelper { @SuppressWarnings("unchecked") - public static Update createMockUpdate() { - Update mockUpdate = mock(Update.class); - when(mockUpdate.from(any(Category.class))).thenReturn(mockUpdate); - when(mockUpdate.where(any(Key.class), any())).thenReturn(mockUpdate); - when(mockUpdate.set(any(Key.class), any())).thenReturn(mockUpdate); - return mockUpdate; - } - - @SuppressWarnings("unchecked") public static Remove createMockRemove() { Remove mockRemove = mock(Remove.class); when(mockRemove.from(any(Category.class))).thenReturn(mockRemove);
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Wed Jan 09 14:59:30 2013 -0500 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Mon Jan 14 14:04:50 2013 -0500 @@ -37,13 +37,12 @@ package com.redhat.thermostat.web.server; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; @@ -73,8 +72,6 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; -import sun.misc.BASE64Encoder; - import com.google.gson.Gson; import com.redhat.thermostat.storage.core.Categories; import com.redhat.thermostat.storage.core.Category; @@ -86,12 +83,12 @@ import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.core.Query.SortDirection; import com.redhat.thermostat.storage.core.Remove; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; import com.redhat.thermostat.storage.model.BasePojo; import com.redhat.thermostat.test.FreePortFinder; import com.redhat.thermostat.test.FreePortFinder.TryPort; -import com.redhat.thermostat.test.MockQuery; import com.redhat.thermostat.web.common.StorageWrapper; import com.redhat.thermostat.web.common.WebInsert; import com.redhat.thermostat.web.common.WebQuery; @@ -136,13 +133,13 @@ private static Key<String> key1; private static Key<Integer> key2; - private static Category category; + private static Category<TestClass> category; @BeforeClass public static void setupCategory() { key1 = new Key<>("key1", true); key2 = new Key<>("key2", false); - category = new Category("test", key1, key2); + category = new Category<>("test", TestClass.class, key1, key2); } @AfterClass @@ -201,42 +198,6 @@ } @Test - public void testFind() throws IOException { - // Configure mock storage. - TestClass expected = new TestClass(); - expected.setKey1("fluff"); - expected.setKey2(42); - when(mockStorage.findPojo(any(Query.class), same(TestClass.class))).thenReturn(expected); - - Query mockQuery = new MockQuery(); - when(mockStorage.createQuery()).thenReturn(mockQuery); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/find-pojo"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setDoInput(true); - conn.setDoOutput(true); - Map<Category,Integer> categoryIdMap = new HashMap<>(); - categoryIdMap.put(category, categoryId); - WebQuery query = (WebQuery) new WebQuery(categoryIdMap).from(category).where(key1, Criteria.EQUALS, "fluff"); - query.setResultClassName(TestClass.class.getName()); - Gson gson = new Gson(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("query="); - out.write(URLEncoder.encode(gson.toJson(query), "UTF-8")); - out.write("\n"); - out.flush(); - - Reader in = new InputStreamReader(conn.getInputStream()); - TestClass result = gson.fromJson(in, TestClass.class); - - assertEquals("fluff", result.getKey1()); - assertEquals(42, result.getKey2()); - verify(mockStorage).createQuery(); - verify(mockStorage).findPojo(any(Query.class), same(TestClass.class)); - } - - @Test public void testFindAllPojos() throws IOException { TestClass expected1 = new TestClass(); expected1.setKey1("fluff1"); @@ -249,9 +210,9 @@ when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); when(cursor.next()).thenReturn(expected1).thenReturn(expected2); - when(mockStorage.findAllPojos(any(Query.class), same(TestClass.class))).thenReturn(cursor); - MockQuery mockQuery = new MockQuery(); - when(mockStorage.createQuery()).thenReturn(mockQuery); + Query mockQuery = mock(Query.class); + when(mockStorage.createQuery(any(Category.class))).thenReturn(mockQuery); + when(mockQuery.execute()).thenReturn(cursor); String endpoint = getEndpoint(); URL url = new URL(endpoint + "/find-all"); @@ -262,9 +223,10 @@ conn.setDoOutput(true); Map<Category,Integer> categoryIdMap = new HashMap<>(); categoryIdMap.put(category, categoryId); - WebQuery query = (WebQuery) new WebQuery(categoryIdMap).from(category).where(key1, Criteria.EQUALS, "fluff") - .sort(key1, SortDirection.DESCENDING).limit(42); - query.setResultClassName(TestClass.class.getName()); + WebQuery query = new WebQuery(categoryId); + query.where(key1, Criteria.EQUALS, "fluff"); + query.sort(key1, SortDirection.DESCENDING); + query.limit(42); Gson gson = new Gson(); OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); String body = "query=" + URLEncoder.encode(gson.toJson(query), "UTF-8"); @@ -279,13 +241,19 @@ assertEquals("fluff2", results[1].getKey1()); assertEquals(43, results[1].getKey2()); - assertTrue(mockQuery.hasSort(key1, SortDirection.DESCENDING)); - assertEquals(42, mockQuery.getLimit()); + verify(mockQuery).where(key1, Criteria.EQUALS, "fluff"); + verify(mockQuery).sort(key1, SortDirection.DESCENDING); + verify(mockQuery).limit(42); + verify(mockQuery).execute(); + verifyNoMoreInteractions(mockQuery); } @Test public void testPutPojo() throws IOException { + Replace replace = mock(Replace.class); + when(mockStorage.createReplace(any(Category.class))).thenReturn(replace); + TestClass expected1 = new TestClass(); expected1.setKey1("fluff1"); expected1.setKey2(42); @@ -299,7 +267,7 @@ conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - WebInsert insert = new WebInsert(categoryId, true, TestClass.class.getName()); + WebInsert insert = new WebInsert(categoryId, true); Gson gson = new Gson(); OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); out.write("insert="); @@ -310,13 +278,14 @@ out.write("\n"); out.flush(); assertEquals(200, conn.getResponseCode()); - verify(mockStorage).putPojo(category, true, expected1); + verify(mockStorage).createReplace(category); + verify(replace).setPojo(expected1); + verify(replace).apply(); } private void sendAuthorization(HttpURLConnection conn, String username, String passwd) { - BASE64Encoder enc = new BASE64Encoder(); String userpassword = username + ":" + passwd; - String encodedAuthorization = enc.encode( userpassword.getBytes() ); + String encodedAuthorization = Base64.encodeBase64String(userpassword.getBytes()); conn.setRequestProperty("Authorization", "Basic "+ encodedAuthorization); } @@ -335,7 +304,7 @@ HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - Map<Category,Integer> categoryIds = new HashMap<>(); + Map<Category<?>,Integer> categoryIds = new HashMap<>(); categoryIds.put(category, categoryId); WebRemove remove = new WebRemove(categoryIds).from(category).where(key1, "test"); Gson gson = new Gson(); @@ -356,10 +325,7 @@ public void testUpdatePojo() throws IOException { Update mockUpdate = mock(Update.class); - when(mockUpdate.from(any(Category.class))).thenReturn(mockUpdate); - when(mockUpdate.where(any(Key.class), any())).thenReturn(mockUpdate); - when(mockUpdate.set(any(Key.class), any())).thenReturn(mockUpdate); - when(mockStorage.createUpdate()).thenReturn(mockUpdate); + when(mockStorage.createUpdate(any(Category.class))).thenReturn(mockUpdate); String endpoint = getEndpoint(); @@ -367,9 +333,13 @@ HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - Map<Category,Integer> categoryIds = new HashMap<>(); - categoryIds.put(category, categoryId); - WebUpdate update = new WebUpdate(categoryIds).from(category).where(key1, "test").set(key1, "fluff").set(key2, 42); + + WebUpdate update = new WebUpdate(); + update.setCategoryId(categoryId); + update.where(key1, "test"); + update.set(key1, "fluff"); + update.set(key2, 42); + Gson gson = new Gson(); OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); out.write("update="); @@ -380,12 +350,12 @@ out.flush(); assertEquals(200, conn.getResponseCode()); - verify(mockStorage).createUpdate(); - verify(mockUpdate).from(category); + verify(mockStorage).createUpdate(category); verify(mockUpdate).where(key1, "test"); verify(mockUpdate).set(key1, "fluff"); verify(mockUpdate).set(key2, 42); - verify(mockStorage).updatePojo(mockUpdate); + verify(mockUpdate).apply(); + verifyNoMoreInteractions(mockUpdate); }