/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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 com.asakusafw.runtime.flow;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ServiceLoader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configurable;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import com.asakusafw.runtime.core.HadoopConfiguration;
import com.asakusafw.runtime.core.legacy.RuntimeResource;
/**
* Manages lifecycle of {@link RuntimeResource} objects.
* @since 0.1.0
* @version 0.7.3
*/
public class RuntimeResourceManager extends Configured {
static final Log LOG = LogFactory.getLog(RuntimeResourceManager.class);
/**
* The standard name of the framework configuration file.
*/
public static final String CONFIGURATION_FILE_NAME = "asakusa-resources.xml"; //$NON-NLS-1$
/**
* The path to configuration file (relative from $ASAKUSA_HOME).
* @since 0.2.5
*/
public static final String CONFIGURATION_FILE_PATH = "core/conf/" + CONFIGURATION_FILE_NAME; //$NON-NLS-1$
private final HadoopConfiguration configuration;
private List<RuntimeResource> resources;
/**
* Creates a new instance.
* @param configuration the current configuration
* @throws IllegalArgumentException if the parameter is {@code null}
*/
public RuntimeResourceManager(Configuration configuration) {
super(configuration);
if (configuration == null) {
throw new IllegalArgumentException("configuration must not be null"); //$NON-NLS-1$
}
this.configuration = new HadoopConfiguration(configuration);
this.resources = Collections.emptyList();
}
/**
* Initializes the managed resources.
* @throws IOException if failed to initialize resources
* @throws InterruptedException if interrupted while initializing resources
* @throws IllegalArgumentException if the configuration is something wrong
* @throws IllegalStateException if the current lifecycle is something wrong
*/
public void setup() throws IOException, InterruptedException {
if (LOG.isDebugEnabled()) {
LOG.debug("Loading runtime plugins"); //$NON-NLS-1$
}
List<? extends RuntimeResource> loaded = load();
this.resources = new ArrayList<>();
for (RuntimeResource resource : loaded) {
if (LOG.isDebugEnabled()) {
LOG.debug(MessageFormat.format(
"Activating runtime plugin: {0}", //$NON-NLS-1$
resource.getClass().getName()));
}
resource.setup(configuration);
resources.add(resource);
}
if (LOG.isDebugEnabled()) {
LOG.debug(MessageFormat.format(
"Loaded {0} runtime plugins", //$NON-NLS-1$
resources.size()));
}
}
/**
* Finalizes and releases the managed resources.
* @throws IOException if failed to finalize resources
* @throws InterruptedException if interrupted while initializing resources
* @throws IllegalArgumentException if the configuration is something wrong
* @throws IllegalStateException if the current lifecycle is something wrong
*/
public void cleanup() throws IOException, InterruptedException {
int count = resources.size();
if (LOG.isDebugEnabled()) {
LOG.debug(MessageFormat.format(
"Unloading {0} runtime plugins", //$NON-NLS-1$
count));
}
try {
for (RuntimeResource resource : resources) {
if (LOG.isDebugEnabled()) {
LOG.debug(MessageFormat.format(
"Deactivating runtime plugin: {0}", //$NON-NLS-1$
resource.getClass().getName()));
}
resource.cleanup(configuration);
}
} finally {
this.resources = Collections.emptyList();
}
if (LOG.isDebugEnabled()) {
LOG.debug(MessageFormat.format(
"Unloaded {0} runtime plugins", //$NON-NLS-1$
count));
}
}
/**
* Loads the available resources.
* In this implementation, the method collects service information from
* {@code META-INF/services/com.asakusafw.runtime.core.RuntimeResource}
* and creates {@link RuntimeResource} implementations on them via SPI.
* @return the loaded resources
* @throws IOException if failed to load the resources
*/
protected List<RuntimeResource> load() throws IOException {
List<RuntimeResource> results = new ArrayList<>();
ClassLoader loader = configuration.getClassLoader();
try {
for (RuntimeResource resource : ServiceLoader.load(RuntimeResource.class, loader)) {
if (resource instanceof Configurable) {
((Configurable) resource).setConf(configuration.getConf());
}
results.add(resource);
}
} catch (RuntimeException e) {
throw new IOException(MessageFormat.format(
"Failed to load resources ({0})",
RuntimeResource.class.getName()),
e);
}
return results;
}
}