blob: 97df47e5bb9cd4cf5940d41b2bc13f1aba6c2da1 [file] [log] [blame]
/*
* 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.datasketches;
import static org.apache.datasketches.Files.isFileValid;
import static org.apache.datasketches.Files.openPrintWriter;
import static org.apache.datasketches.common.Util.getResourcePath;
import static org.apache.datasketches.common.Util.milliSecToString;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;
/**
* This class parses an input string job file, which contains properties for a specific
* JobProfile, and then loads and runs the JobProfile.
*
* @author Lee Rhodes
*/
public class Job {
static final String LS = System.getProperty("line.separator");
private Properties prop;
//Output to Files
private PrintWriter pw = null;
private PrintWriter pwData = null;
//Date-Time
private SimpleDateFormat fileSimpleDateFmt; //used in the filename
private SimpleDateFormat readableSimpleDateFmt; //for human readability
private GregorianCalendar gCal;
private long startTime_mS;
private JobProfile profile;
private final String profileName;
/**
* Build properties and run the Job Profile
*
* @param jobConfigureFileName the name of the text configuration file containing the properties for the
* JobProfile to be run.
*/
public Job(final String jobConfigureFileName) {
final String jobConfStr;
if (isFileValid(jobConfigureFileName)) { //assumes fully qualified
jobConfStr = Files.fileToString(jobConfigureFileName); //includes line feeds
} else {
final String path = getResourcePath(jobConfigureFileName); //try resources
jobConfStr = Files.fileToString(path); //includes line feeds
}
prop = parseJobProperties(jobConfStr);
profile = createJobProfile();
profileName = profile.getClass().getSimpleName();
setDateFormats();
configurePrintWriters();
if (pw == null || pwData == null) {
throw new IllegalStateException("Could not configure PrintWriters.");
}
println("START JOB " + profileName );
flush(); //flush print buffer
/***RUN THE PROFILE ****************/
startTime_mS = System.currentTimeMillis();
profile.start(this);
final long testTime_mS = System.currentTimeMillis() - startTime_mS;
/***********************************/
println("PROPERTIES:");
println(prop.extractKvPairs(LS));
println("Total Job Time : " + milliSecToString(testTime_mS));
println("END JOB " + profileName + LS + LS);
flush();
pw.close();
pwData.close();
}
/**
* Gets a human-readable date string given the time in milliseconds.
* @param timeMillisec the given time generated from System.currentTimeMillis().
* @return the date string
*/
public String getReadableDateString(final long timeMillisec) {
gCal.setTimeInMillis(timeMillisec);
return readableSimpleDateFmt.format(gCal.getTime());
}
/**
* Gets the start time in milliseconds
* @return the start time in milliseconds
*/
public long getStartTime() {
return startTime_mS;
}
/**
* Gets the Properties class.
* @return the Properties class.
*/
public Properties getProperties() {
return prop;
}
/**
* Outputs a string to the configured PrintWriter and stdOut.
* @param obj The obj.toString() to print
*/
public final void print(final Object obj) {
System.out.print(obj.toString());
pw.print(obj.toString());
}
/**
* Outputs a string to the configured PrintWriter for data and stdOut.
* @param obj The obj.toString() to print
*/
public final void printData(final Object obj) {
System.out.print(obj.toString());
pwData.print(obj.toString());
}
/**
* Outputs a line to the configured PrintWriter and stdOut.
* @param obj The obj.toString() to print
*/
public final void println(final Object obj) {
System.out.println(obj.toString());
pw.println(obj.toString());
}
/**
* Outputs a line to the configured PrintWriter for data and stdOut.
* @param obj The obj.toString() to print
*/
public final void printlnData(final Object obj) {
System.out.println(obj.toString());
pwData.println(obj.toString());
}
/**
* Outputs a formatted set of arguments to PrintWriter and stdOut.
* @param format the format specification
* @param args the list of objects
*/
public final void printf(final String format, final Object ...args) {
System.out.printf(format, args);
pw.printf(format, args);
}
/**
* Outputs a formatted set of arguments to PrintWriter for data and stdOut.
* @param format the format specification
* @param args the list of objects
*/
public final void printfData(final String format, final Object ...args) {
System.out.printf(format, args);
pwData.printf(format, args);
}
/**
* Flush any buffered output to the configured PrintWriters.
*/
public final void flush() {
pw.flush();
pwData.flush();
}
public final PrintWriter getPrintWriter() {
return pw;
}
public final PrintWriter getDataPrintWriter() {
return pwData;
}
/**
* Each job is assigned a new Properties class, which is simply a hash map of string
* key value pairs. The pairs are separated by System.getProperty("line.separator").
* The key is separated from the value by "=". Comments start with "#" and continue to the
* end of the line.
* @param jobStr the all the properties as a single string
*/
private static final Properties parseJobProperties(final String jobStr) {
final Properties prop = new Properties();
final String[] lines = jobStr.split(LS);
for (int i = 0; i < lines.length; i++) {
final String line = lines[i].trim();
final int commentIdx = line.indexOf('#');
final String tmp;
if (commentIdx >= 0) { //comment
tmp = line.substring(0, commentIdx).trim();
} else {
tmp = line;
}
if (tmp.length() < 3) { continue; }
final String[] kv = tmp.split("=", 2);
if (kv.length < 2) {
throw new IllegalArgumentException("Missing valid key-value separator: " + tmp);
}
prop.put(kv[0].trim(), kv[1].trim());
}
return prop;
}
/**
* Set two date formats into the Properties file.
* The default date format for the output file name is "yyyyMMdd'_'HHmmssz".
* This can be overridden using the key "FileNameDateFormat".
*
* <p>The default date format for the reports is "yyyy/MM/dd HH:mm:ss z".
* This can be overridden using the key "ReadableDateFormat".
*
* <p>The default time-zone is GMT, with an TimeZoneOffset of zero.
* This can be overridden using the key "TimeZone" for the 3 letter abreviation of the time
* zone name, and the key "TimeZoneOffset" to specify the offset in milliseconds.
*/
private final void setDateFormats() {
String fileSdfStr = prop.get("FileNameDateFormat");
if (fileSdfStr == null) {
fileSdfStr = "yyyyMMdd'_'HHmmssz";
prop.put("FileNameDateFormat", "yyyyMMdd'_'HHmmssz");
}
fileSimpleDateFmt = new SimpleDateFormat(fileSdfStr);
String readableSdfStr = prop.get("ReadableDateFormat");
if (readableSdfStr == null) {
readableSdfStr = "yyyy/MM/dd HH:mm:ss z";
prop.put("ReadableDateFormat", readableSdfStr);
}
readableSimpleDateFmt = new SimpleDateFormat(readableSdfStr);
String timeZoneStr = prop.get("TimeZone");
if (timeZoneStr == null) {
timeZoneStr = "GMT";
prop.put("TimeZone", timeZoneStr);
}
String tzOffsetStr = prop.get("TimeZoneOffset");
if (tzOffsetStr == null) {
tzOffsetStr = "0";
prop.put("TimeZoneOffset", tzOffsetStr);
}
final int timeZoneOffset = Integer.parseInt(tzOffsetStr);
final SimpleTimeZone stz = new SimpleTimeZone(timeZoneOffset, timeZoneStr);
fileSimpleDateFmt.setTimeZone(stz);
readableSimpleDateFmt.setTimeZone(stz);
gCal = new GregorianCalendar(stz);
gCal.setFirstDayOfWeek(java.util.Calendar.SUNDAY); //Sun = 1, Sat = 7
}
private final JobProfile createJobProfile() {
final String profileStr = prop.mustGet("JobProfile");
final JobProfile profile;
try {
final Class<?> clazz = Class.forName(profileStr);
profile = (JobProfile) clazz.getDeclaredConstructor().newInstance();
} catch (final Exception e) {
throw new RuntimeException("Cannot instantiate " + profileStr + "\n" + e);
}
return profile;
}
/**
* Called from constructor to configure the Print Writer
*/
private final void configurePrintWriters() {
//create file name
gCal.setTimeInMillis(System.currentTimeMillis());
final String nowStr = fileSimpleDateFmt.format(gCal.getTime());
final String outputFileName = profileName + nowStr + ".txt";
final String outputFileNameData = profileName + nowStr + ".tsv";
prop.put("OutputFileName", outputFileName);
prop.put("OutputFileNameData", outputFileNameData);
pw = openPrintWriter(outputFileName);
pwData = openPrintWriter(outputFileNameData);
}
/**
* The JVM may call this method to close the PrintWriter resources.
*/
/* DEPRECATED in Object since java 9
@Override
protected void finalize() throws Throwable {
try {
if (pw != null) {
pw.close();
}
if (pwData != null) {
pwData.close();
}
} finally {
super.finalize();
}
}
*/
/**
* Run multiple jobs from the command line
* @param args the configuration file names to be run
*/
@SuppressWarnings("unused")
public static void main(final String[] args) {
for (int j = 0; j < args.length; j++) {
new Job(args[j]);
}
}
}