/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.falcon.unit;
import org.apache.commons.io.FileUtils;
import org.apache.falcon.FalconException;
import org.apache.falcon.entity.store.ConfigurationStore;
import org.apache.falcon.hadoop.JailedFileSystem;
import org.apache.falcon.security.CurrentUser;
import org.apache.falcon.service.FalconJPAService;
import org.apache.falcon.service.ServiceInitializer;
import org.apache.falcon.tools.FalconStateStoreDBCLI;
import org.apache.falcon.util.RuntimeProperties;
import org.apache.falcon.util.StartupProperties;
import org.apache.falcon.util.StateStoreProperties;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocalFileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.oozie.action.hadoop.LauncherMapper;
import org.apache.oozie.local.LocalOozie;
import org.apache.oozie.service.Services;
import org.apache.oozie.util.XConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* FalconUnit runs jobs in an Local Mode and Cluster mode . <p/> Falon Unit is meant for development/debugging purposes
* only.
*/
public final class FalconUnit {
private static final Logger LOG = LoggerFactory.getLogger(FalconUnit.class);
private static final String OOZIE_SITE_XML = "oozie-site.xml";
private static final String OOZIE_DEFAULT_XML = "oozie-default.xml";
private static final String STORAGE_URL = "jail://global:00";
private static final String OOZIE_HOME_DIR = "/tmp/oozie-" + System.getProperty("user.name");
private static JailedFileSystem jailedFileSystem = new JailedFileSystem();
private static final ServiceInitializer STARTUP_SERVICES = new ServiceInitializer();
private static Map<String, String> sysProps;
private static FalconUnitClient falconUnitClient;
private static boolean isLocalMode;
private static boolean isFalconUnitActive = false;
private static final String DB_BASE_DIR = "target/test-data/persistenceDB";
protected static final String DB_LOCATION = DB_BASE_DIR + File.separator + "data.db";
protected static final String URL = "jdbc:derby:"+ DB_LOCATION +";create=true";
protected static final String DB_SQL_FILE = DB_BASE_DIR + File.separator + "out.sql";
protected static final LocalFileSystem LOCAL_FS = new LocalFileSystem();
private FalconUnit() {
}
public static synchronized void start(boolean isLocal) throws Exception {
if (isFalconUnitActive) {
throw new IllegalStateException("Falcon Unit is already initialized");
}
isLocalMode = isLocal;
//Initialize Startup and runtime properties
LOG.info("Initializing startup properties ...");
StartupProperties.get();
LOG.info("Initializing runtime properties ...");
RuntimeProperties.get();
setupExtensionConfigs();
//Initializing Services
STARTUP_SERVICES.initialize();
ConfigurationStore.get();
if (isLocalMode) {
setupOozieConfigs();
initFileSystem();
}
isFalconUnitActive = true;
}
public static void setupExtensionConfigs() throws Exception {
String configPath = new URI(StartupProperties.get().getProperty("config.store.uri")).getPath();
String location = configPath + "-extensionSore";
StartupProperties.get().setProperty("config.store.uri", location);
FileUtils.deleteDirectory(new File(location));
StateStoreProperties.get().setProperty(FalconJPAService.URL, URL);
Configuration localConf = new Configuration();
LOCAL_FS.initialize(LocalFileSystem.getDefaultUri(localConf), localConf);
LOCAL_FS.mkdirs(new Path(DB_BASE_DIR));
createDB(DB_SQL_FILE);
}
public static void createDB(String file) {
File sqlFile = new File(file);
String[] argsCreate = {"create", "-sqlfile", sqlFile.getAbsolutePath(), "-run"};
new FalconStateStoreDBCLI().run(argsCreate);
}
private static void initFileSystem() throws IOException {
Configuration conf = new Configuration();
conf.set("fs.defaultFS", STORAGE_URL);
jailedFileSystem.initialize(LocalFileSystem.getDefaultUri(conf), conf);
}
private static void setupOozieConfigs() throws IOException {
sysProps = new HashMap<>();
String oozieHomeDir = OOZIE_HOME_DIR;
String oozieConfDir = oozieHomeDir + "/conf";
String oozieHadoopConfDir = oozieConfDir + "/hadoop-conf";
String oozieActionConfDir = oozieConfDir + "/action-conf";
String oozieLogsDir = oozieHomeDir + "/logs";
String oozieDataDir = oozieHomeDir + "/data";
LOCAL_FS.mkdirs(new Path(oozieHomeDir));
LOCAL_FS.mkdirs(new Path(oozieConfDir));
LOCAL_FS.mkdirs(new Path(oozieHadoopConfDir));
LOCAL_FS.mkdirs(new Path(oozieActionConfDir));
LOCAL_FS.mkdirs(new Path(oozieLogsDir));
LOCAL_FS.close();
setSystemProperty("oozie.home.dir", oozieHomeDir);
setSystemProperty("oozie.data.dir", oozieDataDir);
setSystemProperty("oozie.action.conf", oozieActionConfDir);
setSystemProperty("oozie.log.dir", oozieLogsDir);
setSystemProperty("oozie.log4j.file", "localoozie-log4j.properties");
setSystemProperty("oozielocal.log", "oozieLogsDir/oozielocal.log");
Configuration oozieSiteConf = new Configuration(false);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream oozieSiteInputStream = classLoader.getResourceAsStream(OOZIE_SITE_XML);
XConfiguration configuration = new XConfiguration(oozieSiteInputStream);
Properties props = configuration.toProperties();
for (String propName : props.stringPropertyNames()) {
oozieSiteConf.set(propName, props.getProperty(propName));
}
oozieSiteInputStream.close();
InputStream oozieDefaultInputStream = classLoader.getResourceAsStream(OOZIE_DEFAULT_XML);
configuration = new XConfiguration(oozieDefaultInputStream);
String classes = configuration.get(Services.CONF_SERVICE_CLASSES);
oozieSiteConf.set(Services.CONF_SERVICE_CLASSES, classes.replaceAll(
"org.apache.oozie.service.ShareLibService,", ""));
File target = new File(oozieConfDir, OOZIE_SITE_XML);
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(target);
oozieSiteConf.writeXml(outStream);
} finally {
if (outStream != null) {
outStream.close();
}
}
oozieDefaultInputStream.close();
CurrentUser.authenticate(System.getProperty("user.name"));
}
public static synchronized void cleanup() throws Exception {
STARTUP_SERVICES.destroy();
if (isLocalMode) {
cleanUpOozie();
jailedFileSystem.close();
}
isFalconUnitActive = false;
}
private static void cleanUpOozie() throws IOException, FalconException {
LocalOozie.stop();
FileUtils.deleteDirectory(new File(OOZIE_HOME_DIR));
// Need to explicitly clean this as Oozie Launcher leaves this behind.
FileUtils.deleteQuietly(new File(LauncherMapper.PROPAGATION_CONF_XML));
resetSystemProperties();
System.setSecurityManager(null);
}
public static synchronized FalconUnitClient getClient() throws FalconException {
if (!isFalconUnitActive) {
throw new IllegalStateException("Falcon Unit is not initialized");
}
if (falconUnitClient == null) {
falconUnitClient = new FalconUnitClient();
}
return falconUnitClient;
}
public static FileSystem getFileSystem() throws IOException {
if (!isFalconUnitActive) {
throw new IllegalStateException("Falcon Unit is not initialized");
}
return jailedFileSystem;
}
// Setting System properties and store their actual values
private static void setSystemProperty(String name, String value) {
if (!sysProps.containsKey(name)) {
String currentValue = System.getProperty(name);
sysProps.put(name, currentValue);
}
if (value != null) {
System.setProperty(name, value);
} else {
System.getProperties().remove(name);
}
}
/**
* Reset changed system properties to their original values.
*/
private static void resetSystemProperties() {
if (sysProps != null) {
for (Map.Entry<String, String> entry : sysProps.entrySet()) {
if (entry.getValue() != null) {
System.setProperty(entry.getKey(), entry.getValue());
} else {
System.getProperties().remove(entry.getKey());
}
}
sysProps.clear();
}
}
}