/* Copyright 2012 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arbeitspferde.groningen;
import com.google.common.util.concurrent.ServiceManager;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.arbeitspferde.groningen.common.Settings;
import org.arbeitspferde.groningen.common.SystemAdapter;
import org.arbeitspferde.groningen.config.ConfigManager;
import org.arbeitspferde.groningen.config.ProtoBufConfigManager;
import org.arbeitspferde.groningen.config.ProtoBufConfigManagerFactory;
import org.arbeitspferde.groningen.config.StubConfigManager;
import org.arbeitspferde.groningen.exceptions.InvalidConfigurationException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Groningen is an autonomic Java performance optimization tool. This class is the
* program entry point and main processing loop. It instantiates singletons that
* represent stages in the iterative processing pipeline. Then it runs the
* processing pipeline until Groningen decides to terminate.
*
*/
@Singleton
public class GroningenWorkhorse implements Runnable {
/** Logger for this class */
private static final Logger log =
Logger.getLogger(GroningenWorkhorse.class.getCanonicalName());
private final ServiceManager backgroundServices;
private final SystemAdapter systemAdapter;
private final Settings settings;
private final ProtoBufConfigManagerFactory protoBufConfigManagerFactory;
private final PipelineManager pipelineManager;
private final Build build;
@Inject
private GroningenWorkhorse(final Provider<Pipeline> pipelineProvider,
final PipelineIdGenerator pipelineIdGenerator,
final ServiceManager backgroundServices,
final SystemAdapter systemAdapter,
final Settings settings,
final PipelineManager pipelineManager,
final ProtoBufConfigManagerFactory protoBufConfigManagerFactory,
final Build build) {
this.backgroundServices = backgroundServices;
this.systemAdapter = systemAdapter;
this.pipelineManager = pipelineManager;
this.settings = settings;
this.protoBufConfigManagerFactory = protoBufConfigManagerFactory;
this.build = build;
}
private ConfigManager createConfigManager(String source) {
if (source == null) {
throw new IllegalArgumentException("null source provided");
}
String [] sourceParts = source.split(":", 2);
if (sourceParts[0].equals("proto")) {
if (sourceParts.length < 2) {
throw new IllegalArgumentException("provided source contained only proto spec, requires "
+ "additional information to instantiate the protobuf config manager");
}
ProtoBufConfigManager manager = protoBufConfigManagerFactory.forPath(sourceParts[1]);
try {
manager.initialize();
} catch (IOException e) {
throw new RuntimeException("I/O error with loading configuration.", e);
} catch (InvalidConfigurationException e) {
throw new RuntimeException("Illegal configuration.", e);
}
return manager;
} else if (source.startsWith("stub:")) {
return new StubConfigManager();
} else {
throw new IllegalArgumentException(source + " not a recongized config type");
}
}
private void startSubservices() {
final int startupDeadline = settings.getStartupSubservicesDeadlineSeconds();
log.info(
String.format("Starting subservices; will wait %s seconds at most...", startupDeadline));
try {
backgroundServices.startAsync().awaitHealthy(startupDeadline, TimeUnit.SECONDS);
} catch (TimeoutException e) {
throw new RuntimeException(e);
}
}
private void stopSubservices() {
try {
final int shutdownDeadline = settings.getShutdownSubservicesDeadlineSeconds();
log.info(String.format(
"Waiting %s seconds for shutdown services to commence...", shutdownDeadline));
backgroundServices.stopAsync().awaitStopped(shutdownDeadline, TimeUnit.SECONDS);
} catch (TimeoutException e) {
throw new RuntimeException(e);
}
}
/**
* Prepare for and then run the processing loop
*/
public void run() {
log.info(build.getStamp());
try {
startSubservices();
for (String configPath : settings.getConfigFileNames()) {
ConfigManager configManager = createConfigManager(configPath);
PipelineId pipelineId = pipelineManager.startPipeline(configManager, true);
Pipeline pipeline = pipelineManager.findPipelineById(pipelineId);
if (pipeline == null) {
throw new RuntimeException(String.format("Pipeline %s died almost immediately",
pipelineId.toString()));
}
}
} catch (RuntimeException e) {
log.log(Level.SEVERE, "Aborted.", e);
try {
stopSubservices();
} catch (RuntimeException stopSubservicesError) {
log.log(Level.SEVERE,
"Could not shutdown subservices in a timely fashion.", stopSubservicesError);
}
systemAdapter.exit(1);
}
}
}