ModelDataService.java [src/csip] Revision: 3af6c48ce47c53e489a005b55aebf48251e622b9 Date: Tue Apr 25 21:50:59 MDT 2017
/*
* $Id$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* a Model-as-a-Service framework, API and application suite.
*
* 2012-2017, Olaf David and others, OMSLab, Colorado State University.
*
* OMSLab licenses this file to you under the MIT license.
* See the LICENSE file in the project root for more information.
*/
package csip;
import com.fasterxml.uuid.Generators;
import static csip.Config.CSIP_ARCHIVE_FAILEDONLY;
import static csip.Config.CSIP_DIR;
import static csip.Config.CSIP_KEEPWORKSPACE;
import static csip.Config.CSIP_LOGGING_STRMAX;
import static csip.Config.CSIP_RESPONSE_STACKTRACE;
import static csip.Config.CSIP_SNAPSHOT;
import static csip.Config.CSIP_TIMEZONE;
import static csip.Config.CSIP_VERSION;
import csip.annotations.*;
import csip.utils.*;
import csip.utils.Services.FormDataParameter;
import java.io.*;
import java.net.URI;
import java.sql.Connection;
import java.text.DateFormat;
import java.time.Duration;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.apache.commons.io.*;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.http.client.utils.URIBuilder;
import org.codehaus.jettison.json.*;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
/**
* Base class for all modeling and data services.
*
* A service implementation will subclass ModelDataService.
*
* @author Olaf David
*/
public abstract class ModelDataService {
// Execution status
public static final String EXEC_OK = null;
public static final String EXEC_FAILED = "Error";
// General const
public static final String KEY_REPORT = "report";
public static final String KEY_METAINFO = "metainfo";
public static final String KEY_PARAMETER = "parameter";
public static final String KEY_RESULT = "result";
//
// metainfo keys
public static final String KEY_PARAMETERSETS = "parametersets";
public static final String KEY_SUUID = "suid";
public static final String KEY_STATUS = "status";
public static final String KEY_NEXT_POLL = "next_poll";
public static final String KEY_FIRST_POLL = "first_poll";
public static final String KEY_CPU_TIME = "cpu_time";
public static final String KEY_CLOUD_NODE = "cloud_node";
public static final String KEY_SERVICE_URL = "service_url";
public static final String KEY_URL = "url";
public static final String KEY_REQ_IP = "request_ip";
public static final String KEY_KEEP_RESULTS = "keep_results";
public static final String KEY_EXPIRATION_DATE = "expiration_date";
public static final String KEY_TSTAMP = "tstamp"; //?
public static final String KEY_TZ = "tz"; // timezone
public static final String KEY_PROGRESS = "progress";
public static final String KEY_STATE = "state";
// parameter keys
public static final String KEY_NAME = "name";
public static final String VALUE = "value";
public static final String KEY_VALUE = "value";
public static final String GEOMETRY = "geometry";
public static final String KEY_UNIT = "unit";
public static final String KEY_DESC = "description";
public static final String KEY_TIME_FILEIO = "timeFileIO";
public static final String KEY_TIME_MODEL = "timeModel";
public static final String KEY_TIME_CLIMATE_QUERY = "timeClimateQuery";
public static final String KEY_TIME_SOIL_QUERY = "timeSoilQuery";
public static final String KEY_TIME_LOGGING = "timeLogging";
public static final String KEY_TIME_TOTAL = "timeTotal";
public static final String KEY_REQUEST_RESULTS = "request-results";
//
public static final String FORM_PARAM = "param";
//
public static final String ERROR = "error";
public static final String OK = "ok";
public static final String IN = "in";
public static final String INTENT = "intent";
public static final String MAX = "max";
public static final String MIN = "min";
public static final String OUT = "out";
public static final String RANGE = "range";
public static final String UNIT = "unit";
// execution stages
public static final String RUNNING = "Running";
public static final String FINISHED = "Finished";
public static final String CANCELED = "Canceled";
public static final String FAILED = "Failed";
public static final String UNKNOWN = "Unknown";
public static final String SUBMITTED = "Submitted";
// execution modes
public static final String SYNC = "sync";
public static final String ASYNC = "async";
public static final String KEY_MODE = "mode";
// Common report constants
public static final String REPORT_FILE = "report.json";
public static final String REQUEST_FILE = ".request.json";
public static final String RESPONSE_FILE = ".response.json";
public static final String LOG_FILE = ".log.txt";
//
public static final String REPORT_TYPE = "type";
public static final String REPORT_VALUE = "value";
public static final String REPORT_NAME = "name";
public static final String REPORT_UNITS = "units";
public static final String REPORT_DESC = "description";
public static final String REPORT_DIM0 = "dimension0";
public static final String REPORT_DIM = "dim";
private final String suid = Generators.timeBasedGenerator().generate().toString();
// protected final Logger LOG = Logger.getLogger(getClass().getAnnotation(Path.class).value());
protected String tz = Config.getString(CSIP_TIMEZONE);
//
//
private File workspace;
private File results;
// private File cache;
//
private JSONObject metainfo;
private JSONObject request;
private JSONArray param;
private Map<String, JSONObject> paramMap;
//
//TODO: make this private.
public Task mt;
private Date start = null;
private String[] inputs = ModelSession.NO_ATTACHMENTS; // no attachments
private String req_host;
private String req_url = "";
private String req_remoteIp = "";
private String req_context;
private String req_scheme;
private JSONArray res;
private JSONArray rep;
// The progress (message) during execution.
private String progress = null;
private String state = null;
// file stuff
private List<File> fres;
private Map<File, String> fdesc;
private List<File> frep;
private static final String AUTO_RUN = "auto";
// options Default comes from @Options
private boolean unpack;
// Timeout of execution in seconds. Default comes from @Options
private long timeout;
protected SessionLogger LOG = new SessionLogger(getResultsDir(), getServicePath(), getSUID());
private static final int PRE = 0;
private static final int PROC = 1;
private static final int POST = 2;
/**
* This is an error. (either an exception or a string).
*/
Throwable serviceError = null;
String digest;
// report
private JSONArray reportData() {
if (rep == null) {
rep = new JSONArray();
}
return rep;
}
private JSONArray results() {
if (res == null) {
res = new JSONArray();
}
return res;
}
private List<File> fresults() {
if (fres == null) {
fres = new ArrayList<>();
}
return fres;
}
private List<File> freports() {
if (frep == null) {
frep = new ArrayList<>();
}
return frep;
}
private Map<File, String> fdesc() {
if (fdesc == null) {
fdesc = new HashMap<>();
}
return fdesc;
}
// /**
// * Get the cache directory.
// *
// * @return The file representing the cache folder.
// */
// private File getCacheDir() {
// if (cache == null) {
// cache = new File(Config.getString("csip.cache.dir", "/tmp/csip/cache"));
// cache.mkdirs();
// if (LOG.isLoggable(Level.INFO)) {
// LOG.info(getServicePath() + " create cache dir: " + cache);
// }
// }
// return cache;
// }
// /**
// * Get a cached file.
// *
// * @param suid The suid of a previous service call.
// * @param filename the file name
// * @return the cached file or null if not exist.
// * @throws Exception
// */
// private File getCachedFile(String suid, String filename) throws Exception {
// File cacheFile = new File(getCacheDir(), suid + File.separator + filename);
// for (int i = 0; i < 3; i++) {
// if (cacheFile.exists()) {
// if (LOG.isLoggable(Level.INFO)) {
// LOG.info("local cache -> workspace: " + suid + "/" + filename);
// }
// File wsFile = new File(getWorkspaceDir(), filename);
// Files.createSymbolicLink(wsFile.toPath(), cacheFile.toPath());
//// FileUtils.copyFile(cacheFile, wsFile);
// return wsFile;
// }
// byte[] data = Config.getCacheStore().getFile(suid, filename);
// if (data == null) {
// return null;
// }
//
// if (LOG.isLoggable(Level.INFO)) {
// LOG.info("redis -> local cache: " + suid + "/" + filename);
// }
// FileUtils.writeByteArrayToFile(cacheFile, data);
//// Files.write(cacheFile.toPath(), data);
// }
// return null;
// }
// /**
// * Add a file to the cache
// *
// * @param file the file to cache
// * @param ttlsec the time to cache it in seconds.
// * @throws Exception If the file does not exists.
// */
// private void setCachedFile(File file, int ttlsec) throws Exception {
// if (!file.exists()) {
// throw new IllegalArgumentException("Not found " + file);
// }
//// byte[] filecontent = FileUtils.readFileToByteArray(file);
// byte[] filecontent = Files.readAllBytes(file.toPath());
// Config.getCacheStore().putFile(suid, file.getName(), filecontent, file.length(), ttlsec);
// }
// private void handleCache(JSONObject tmp_metainfo) throws Exception {
// if (tmp_metainfo.has("cache")) {
// // fill the cache
// String c = tmp_metainfo.getString("cache");
// String[] cinfo = c.split("\\s+");
// if (cinfo.length < 2) {
// throw new ServiceException("Invalid cache request: " + c);
// }
// int ttlsec = 300;
// try {
// ttlsec = Integer.parseInt(cinfo[0]);
// } catch (NumberFormatException E) {
// throw new ServiceException("Invalid cache ttl value: " + ttlsec);
// }
// for (int i = 1; i < cinfo.length; i++) {
// String file = cinfo[i];
// // files should be in the workspace by now
// File f = new File(getWorkspaceDir(), file);
// if (!f.exists()) {
// throw new ServiceException("Not found for caching: " + f.toString());
// }
// setCachedFile(f, ttlsec);
// LOG.log(Level.INFO, "Cached " + f + " for " + ttlsec + " seconds.");
// }
// } else if (tmp_metainfo.has("cached")) {
// // fetch the cache
// String c = tmp_metainfo.getString("cached");
// String[] cinfo = c.split("\\s+");
// if (cinfo.length < 2) {
// throw new ServiceException("Invalid cache request: " + c);
// }
// String c_suid = cinfo[0];
// for (int i = 1; i < cinfo.length; i++) {
// String file = cinfo[i];
// File f = getCachedFile(c_suid, file);
// if (f == null) {
// throw new ServiceException("failed to fetch from cache: " + file);
// }
// }
// }
// }
///////////////////////////////////////////////////////////////////// URL/ Paths
/**
* The request ip
* @return the request ip
*/
protected final String getRemoteAddr() {
return req_remoteIp;
}
/**
* Get the codebase without the model service path
* @return the codebase of the URL as String
*/
protected final String getCodebase() {
String m = getServicePath();
String u = getRequestURL();
return u.substring(0, u.indexOf(m));
}
/**
* Provide the service path name, e.g. 'weps/1.0'
* @return the model service path
*/
protected final String getServicePath() {
Path p = getClass().getAnnotation(Path.class);
if (p != null) {
return p.value();
}
throw new RuntimeException("@Path annotation missing for " + getClass());
}
/**
* Provide the state if this service. It picks up the @Deprecated or the
* @State annotation.
*
* @return the state, or null if not defined.
*/
private final String getState() {
return Utils.getServiceState(getClass());
}
/**
* Get the complete request URL
* @return the full request URL
*/
protected synchronized final String getRequestURL() {
return req_url;
}
/**
* Get the complete request URL
* @return the full request URL
*/
protected final String getRequestHost() {
return req_host;
}
/**
* Get the webapp context name.
* @return the context name
*/
protected final String getRequestContext() {
return req_context;
}
/**
* Get the webapp context name.
* @return the context name
*/
protected final String getRequestScheme() {
return req_scheme;
}
/**
* Indicate if the service needs a workspace folder (as sandbox)
* @return true if it is needed, false otherwise.
*/
protected final boolean hasWorkspaceDir() {
return workspace != null;
}
/**
* Indicate if the service needs a separate result folder.
* @return true if it is needed, false otherwise.
*/
private boolean hasResultsDir() {
return results != null;
}
////////////////////////////////////////////////////////////////////// Lifecycle
/**
* workflow step 1: process the request data.
* @throws Exception
*/
protected void preProcess() throws Exception {
}
/**
* workflow step 2: The process method.
* @throws Exception
*/
protected void doProcess() throws Exception {
}
/**
* workflow step 3: create the response the data.
* @throws Exception
*/
protected void postProcess() throws Exception {
}
////////////////////////////////////////////////////////////////////
private Throwable preProcess0() throws Exception {
return doProcessWrapper(PRE);
}
// /**
// * Create a callable model run. The callable is returning a string result.
// * The string is 'null' if the model execution succeeded. It is not 'null'
// * if there is an error and the string may contain the error message.
// *
// * @return a callable
// * @throws Exception if an error occurred during execution.
// */
@Deprecated
public Callable<Throwable> createCallable() throws Exception {
return () -> {
return process0();
};
}
/**
* Process logic of the service.
* @return null if the process ended successfully, the error message
* otherwise.
* @throws Exception
* @deprecated use doProcess() instead.
*/
@Deprecated
protected String process() throws Exception {
return EXEC_OK;
}
/**
* This replaces the process() call from process0
*/
private Throwable doProcessWrapper(int phase) {
try {
switch (phase) {
case PRE:
preProcess();
break;
case PROC:
doProcess(); // preferred
String ret = process(); // deprecated
if (ret != null) {
return new ServiceException(ret);
}
break;
case POST:
postProcess();
break;
}
} catch (Throwable E) {
return E;
}
return null;
}
private void processOptions() {
// fetching the defaults
try {
unpack = (boolean) Options.class.getMethod("unpackinput").getDefaultValue();
String to = (String) Options.class.getMethod("timeout").getDefaultValue();
timeout = Duration.parse(to).getSeconds();
} catch (Exception ex) {
// this should not happen.
LOG.log(Level.SEVERE, null, ex);
}
Options opt = getClass().getAnnotation(Options.class);
if (opt != null) {
// overwritten.
unpack = opt.unpackinput();
try {
timeout = Duration.parse(opt.timeout()).getSeconds();
} catch (DateTimeParseException E) {
LOG.warning("illegal timeout: " + opt.timeout());
}
}
}
private Throwable process0() throws Exception {
Resource[] resources = Binaries.getResourcesByType(getClass(), ResourceType.OMS_COMP);
if (resources.length > 0) {
Class<?> cl = getClass();
if (!resources[0].file().isEmpty()) {
String classname = resources[0].file();
cl = Thread.currentThread().getContextClassLoader().loadClass(classname);
}
try {
OMSComponentMapper cm = new OMSComponentMapper(cl.newInstance());
cm.setInputs(this);
cm.process();
cm.getOutputs(this);
} catch (Throwable T) {
return T;
}
return null;
}
Resource resource = Binaries.getResourceById(getClass(), AUTO_RUN);
if (resource == null) {
return doProcessWrapper(PROC);
}
Executable e = null;
if (resource.type() == ResourceType.EXECUTABLE) {
e = Binaries.getResourceExe0(getClass(), AUTO_RUN, getWorkspaceDir(), LOG);
} else if (resource.type() == ResourceType.CLASSNAME || resource.type() == ResourceType.OMS_DSL) {
List<File> jars = new ArrayList<>();
File csip_home = new File(Config.getString(CSIP_DIR, "/tmp/csip"));
Resource[] r = Binaries.getResourcesByType(getClass(), ResourceType.JAR);
for (Resource j1 : r) {
// be aware of the underscore in a jar file.
jars.add(Binaries.unpackResource0(j1, csip_home, LOG)); // Binaries.unpackResource("/oms-all.jar_", new File(oms_home, "oms-all.jar"));
}
if (resource.type() == ResourceType.OMS_DSL) {
e = Binaries.getResourceOMSDSL(getClass(), AUTO_RUN, getWorkspaceDir(), jars, LOG);
} else {
e = Binaries.getResourceJava(getClass(), AUTO_RUN, getWorkspaceDir(), jars, LOG);
}
}
LOG.info("running : " + e.getName());
int ret = e.exec();
LOG.info("done with exit value: " + ret);
if (ret == 0) {
return null;
}
FilenameFilter ff = new WildcardFileFilter("*" + Binaries.STDERR, IOCase.INSENSITIVE);
File[] f = getWorkspaceDir().listFiles(ff);
if (f != null && f.length > 0) {
return new ServiceException(FileUtils.readFileToString(f[0]));
}
return new ServiceException(EXEC_FAILED + " return code " + ret);
}
private Throwable postProcess0() throws Exception {
for (Resource r : Binaries.getResourcesByType(getClass(), ResourceType.OUTPUT)) {
String[] files = r.file().split("\\s+");
FilenameFilter ff = new WildcardFileFilter(files, IOCase.INSENSITIVE);
putResult(getWorkspaceDir().listFiles(ff));
}
return doProcessWrapper(POST);
}
/**
* Step 4: Create the results as JSON, (deprecated)
* @return the results as an array of JSON objects.
* @throws Exception
* @deprecated replaced by {@link #postProcess()}
*/
@Deprecated
protected JSONArray createResults() throws Exception {
return null;
}
/**
* Create a report.
* @return The report content as JSONArray
* @throws Exception
* @deprecated replaced by {@link #report()}
*/
@Deprecated
protected JSONArray createReport() throws Exception {
return null;
}
/**
* Create a report.
*
* @throws Exception
*/
protected void report() throws Exception {
}
/**
* Return the recommended polling interval for async calls in milliseconds.
* @return the polling interval value in milliseconds
*/
protected long getNextPoll() {
Polling p = getClass().getAnnotation(Polling.class);
if (p != null) {
return p.next();
}
return -1;
}
/**
* Get the time until first poll for async calls in milliseconds.
* @return time to first poll in milliseconds
*/
protected long getFirstPoll() {
Polling p = getClass().getAnnotation(Polling.class);
if (p != null) {
return p.first();
}
return -1;
}
/**
* Get a new Workspace folder for this model run. returns null if it has no
* simulation folder.
* @return the workspace or null if there should be none.
*/
protected final File getWorkspaceDir() {
if (workspace == null) {
workspace = Services.getWorkDir(suid);
workspace.mkdirs();
// if (LOG.isLoggable(Level.INFO)) {
// LOG.info("create workspace dir: " + workspace);
// }
}
return workspace;
}
/**
* Get a file from the workspace. You can specify workspace sub-folders in
* the name (use always a slash as file separator).
* @param name
* @return A file object from the workspace.
*/
protected final File getWorkspaceFile(String name) {
return new File(getWorkspaceDir(), name);
}
/**
* Get a new Results folder for this model run. returns null if it has no
* results folder.
* @return the results folder or null if there should be none.
*/
private File getResultsDir() {
if (results == null) {
results = Services.getResultsDir(suid);
results.mkdirs();
// if (LOG.isLoggable(Level.INFO)) {
// LOG.info("create results dir: " + results);
// }
}
return results;
}
/**
* Get the simulation unique identifier (128 byte UUID)
* @return the suid string
*/
protected final String getSUID() {
return suid;
}
/**
* Get the request metainfo.
* @return the metainfo
*/
protected final JSONObject getMetainfo() {
return metainfo;
}
/**
* Get the request parameter
* @return request parameter
*/
protected final JSONArray getParam() {
return param;
}
/**
* Set the request metainfo.
* @param mi
* @deprecated
*/
@Deprecated
public final void setMetainfo(JSONObject mi) {
metainfo = mi;
}
/**
* Set the request parameter.
* @param parameter
* @deprecated
*/
@Deprecated
public void setParam(JSONArray parameter) {
param = parameter;
}
/**
* Set the request
* @param req
* @deprecated
*/
@Deprecated
public final void setRequest(JSONObject req) {
request = req;
}
/**
* Set the Parameter map
* @deprecated
*/
@Deprecated
public final void setParamMap(Map<String, JSONObject> pm) {
paramMap = pm;
}
/**
* Get the Parameter as map "name" to "JSONObject"
* @return the parameter map
*/
protected final Map<String, JSONObject> getParamMap() {
return paramMap;
}
/**
* Get the original JSOn request object.
* @return the request object.
*/
protected final JSONObject getRequest() {
return request;
}
/////////////////////////////////////////////////////////////////// metainfo
/**
* Get the metainfo value as String.
* @param name the name of the metainfo entry
* @return the value of a metainfo entry
* @throws ServiceException
*/
protected String getStringMetainfo(String name) throws ServiceException {
try {
return getMetainfo().getString(name);
} catch (JSONException ex) {
throw new ServiceException(ex);
}
}
/**
* Get metainfo value as int.
* @param name the name of the metainfo entry
* @return the int value of a metainfo entry.
* @throws ServiceException
*/
protected int getIntMetainfo(String name) throws ServiceException {
try {
return getMetainfo().getInt(name);
} catch (JSONException ex) {
throw new ServiceException(ex);
}
}
/**
* Get the metainfo value as double.
* @param name the name of the metainfo entry
* @return the metainfo value.
* @throws ServiceException
*/
protected double getDoubleMetainfo(String name) throws ServiceException {
try {
return getMetainfo().getDouble(name);
} catch (JSONException ex) {
throw new ServiceException(ex);
}
}
/**
* Get a metainfo value as boolean
* @param name the name of the metainfo entry
* @return the metainfo value
* @throws ServiceException
*/
protected boolean getBooleanMetainfo(String name) throws ServiceException {
try {
return getMetainfo().getBoolean(name);
} catch (JSONException ex) {
throw new ServiceException(ex);
}
}
/**
* Check if a metainfo entry exists.
* @param name the name of a metainfo name.
* @return true if a metainfo entry exists, false otherwise
*/
protected boolean hasMetainfo(String name) {
return getMetainfo().has(name);
}
/**
* Get all metainfo names.
* @return the set of metainfo names.
*/
protected Set<String> getMetainfoNames() {
Set<String> s = new TreeSet<>();
Iterator<?> i = getMetainfo().keys();
while (i.hasNext()) {
s.add(i.next().toString());
}
return s;
}
/**
* Get the number of metainfo entries.
* @return the number of entries.
*/
protected int getMetainfoCount() {
return getMetainfo().length();
}
protected void setMetainfoWarning(String msg) throws ServiceException {
try {
getMetainfo().put("warning", msg);
} catch (JSONException ex) {
throw new ServiceException("Warning failed.");
}
}
protected void appendMetainfoWarning(String msg) throws ServiceException {
try {
String prevmsg = JSONUtils.getJSONString(getMetainfo(), "warning", "");
prevmsg += "|" + msg;
getMetainfo().put("warning", prevmsg);
} catch (JSONException ex) {
throw new ServiceException("Warning failed.");
}
}
///////////////////////////////////////////////////////////////// files handling
/**
* Get the attached files for this request. This includes the request.
* @return The set of files.
*/
protected Set<File> getFileInputs() {
Set<File> f = new TreeSet<>();
for (String att : inputs) {
File file = new File(getWorkspaceDir(), att);
if (file.exists()) {
f.add(file);
}
}
return f;
}
/**
* Get the number of attachments. This includes the request.
* @return the number of files attached.
*/
protected int getFileInputsCount() {
return inputs.length;
}
/**
* Check is a input file exists in the workspace.
*
* @param name the file name
* @return true if the file exist, false otherwise
* @throws ServiceException
*/
protected boolean hasFileInput(String name) throws ServiceException {
return getFileInput(name) != null;
}
/**
* Get a file object for a given file name.
* @param name the file name (no path)
* @return the file object with its absolute file path within the workspace.
* It returns null if the file is not input or does not exist.
* @throws csip.ServiceException
*/
protected File getFileInput(String name) throws ServiceException {
if (!Arrays.asList(inputs).contains(name)) {
return null;
}
File f = new File(getWorkspaceDir(), name);
if (f.exists()) {
return f;
}
throw new ServiceException("Missing File: " + name);
}
///////////////////////////////////////////////////////////// parameter handling
/**
* Check if a parameter exists.
* @param name the name of the parameter entry
* @return true if present false otherwise.
*/
protected boolean hasParam(String name) {
return getParamMap().containsKey(name);
}
/**
* Check is a required parameter exists.
*
* @param name
*/
protected void requiredParam(String name) throws ServiceException {
if (!hasParam(name)) {
throw new ServiceException("Parameter not found :" + name);
}
}
/**
* Get the number of parameter.
* @return the number of parameter
*/
protected int getParamCount() {
return getParamMap().size();
}
/**
* Get all parameter names.
* @return the set of names.
*/
protected Set<String> getParamNames() {
return getParamMap().keySet();
}
/**
* Get a String parameter
* @param name the parameter name
* @return the parameter value as String
* @throws ServiceException
*/
protected String getStringParam(String name) throws ServiceException {
try {
return getParam(name).getString(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a String parameter.
* @param name the name of the parameter
* @param def the default value if the parameter is missing
* @return the value of the parameter
* @throws ServiceException
*/
protected String getStringParam(String name, String def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : p.getString(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get an int parameter.
* @param name the parameter name
* @return the parameter value as int
* @throws ServiceException
*/
protected int getIntParam(String name) throws ServiceException {
try {
return getParam(name).getInt(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a int parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the int value of the parameter.
* @throws ServiceException
*/
protected int getIntParam(String name, int def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : p.getInt(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get an double parameter
* @param name the parameter name
* @return the parameter value as double
* @throws ServiceException
*/
protected double getDoubleParam(String name) throws ServiceException {
try {
return getParam(name).getDouble(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a double parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the double value of the parameter
* @throws ServiceException
*/
protected double getDoubleParam(String name, double def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : p.getDouble(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a boolean parameter.
* @param name the parameter name.
* @return the parameter value as boolean.
* @throws ServiceException
*/
protected boolean getBooleanParam(String name) throws ServiceException {
try {
return getParam(name).getBoolean(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a Boolean parameter.
* @param name the name of the parameter
* @param def the default value.
* @return the boolean value of the parameter.
* @throws ServiceException
*/
protected boolean getBooleanParam(String name, boolean def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : p.getBoolean(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a long parameter.
* @param name the parameter name.
* @return the parameter value as long.
* @throws ServiceException
*/
protected long getLongParam(String name) throws ServiceException {
try {
return getParam(name).getLong(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a Long parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the long value of the parameter
* @throws ServiceException
*/
protected long getLongParam(String name, long def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : p.getLong(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a JSONObject parameter.
* @param name the parameter name.
* @return the parameter value as JSONObject.
* @throws ServiceException
*/
protected JSONObject getJSONParam(String name) throws ServiceException {
try {
return getParam(name).getJSONObject(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a Long parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the JSONObject of the parameter
* @throws ServiceException
*/
protected JSONObject getJSONParam(String name, JSONObject def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : p.getJSONObject(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a JSONArray parameter.
* @param name the parameter name.
* @return the parameter value as JSONObject.
* @throws ServiceException
*/
protected JSONArray getJSONArrayParam(String name) throws ServiceException {
try {
return getParam(name).getJSONArray(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a Long parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the JSONObject of the parameter
* @throws ServiceException
*/
protected JSONArray getJSONArrayParam(String name, JSONArray def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : p.getJSONArray(VALUE);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a int[] parameter.
* @param name the parameter name.
* @return the parameter value as JSONObject.
* @throws ServiceException
*/
protected int[] getIntArrayParam(String name) throws ServiceException {
try {
JSONArray a = getParam(name).getJSONArray(VALUE);
return JSONUtils.toIntArray(a);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a int[] parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the JSONObject of the parameter
* @throws ServiceException
*/
protected int[] getIntArrayParam(String name, int[] def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : JSONUtils.toIntArray(p.getJSONArray(VALUE));
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a boolean[] parameter.
* @param name the parameter name.
* @return the parameter value as JSONObject.
* @throws ServiceException
*/
protected boolean[] getBooleanArrayParam(String name) throws ServiceException {
try {
JSONArray a = getParam(name).getJSONArray(VALUE);
return JSONUtils.toBooleanArray(a);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a boolean[] parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the JSONObject of the parameter
* @throws ServiceException
*/
protected boolean[] getBooleanArrayParam(String name, boolean[] def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : JSONUtils.toBooleanArray(p.getJSONArray(VALUE));
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a long[] parameter.
* @param name the parameter name.
* @return the parameter value as JSONObject.
* @throws ServiceException
*/
protected long[] getLongArrayParam(String name) throws ServiceException {
try {
JSONArray a = getParam(name).getJSONArray(VALUE);
return JSONUtils.toLongArray(a);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a long[] parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the JSONObject of the parameter
* @throws ServiceException
*/
protected long[] getLongArrayParam(String name, long[] def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : JSONUtils.toLongArray(p.getJSONArray(VALUE));
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a String[] parameter.
* @param name the parameter name.
* @return the parameter value as JSONObject.
* @throws ServiceException
*/
protected String[] getStringArrayParam(String name) throws ServiceException {
try {
JSONArray a = getParam(name).getJSONArray(VALUE);
return JSONUtils.toStringArray(a);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a String[] parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the JSONObject of the parameter
* @throws ServiceException
*/
protected String[] getStringArrayParam(String name, String[] def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : JSONUtils.toStringArray(p.getJSONArray(VALUE));
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a double[] parameter.
* @param name the parameter name.
* @return the parameter value as JSONObject.
* @throws ServiceException
*/
protected double[] getDoubleArrayParam(String name) throws ServiceException {
try {
JSONArray a = getParam(name).getJSONArray(VALUE);
return JSONUtils.toDoubleArray(a);
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get a double[] parameter.
* @param name the name of the parameter
* @param def the default value if parameter does not exist
* @return the JSONObject of the parameter
* @throws ServiceException
*/
protected double[] getDoubleArrayParam(String name, double[] def) throws ServiceException {
try {
JSONObject p = getParamMap().get(name);
return (p == null) ? def : JSONUtils.toDoubleArray(p.getJSONArray(VALUE));
} catch (JSONException ex) {
throw new ServiceException("No Value for " + name, ex);
}
}
/**
* Get the unit of a parameter.
* @param name the parameter name
* @return the unit as string, 'null' if there is none.
* @throws ServiceException
*/
protected String getParamUnit(String name) throws ServiceException {
try {
return getParam(name).getString(UNIT);
} catch (JSONException ex) {
throw new ServiceException("No unit for " + name);
}
}
/**
* Get the description of a parameter.
* @param name the parameter name
* @return the description as string, 'null' if there is none.
* @throws ServiceException
*/
protected String getParamDescr(String name) throws ServiceException {
try {
return getParam(name).getString(KEY_DESC);
} catch (JSONException ex) {
throw new ServiceException("No description for " + name);
}
}
/**
* Get the geometry of a parameter
* @param name the name if the parameter
* @return the geometry of a parameter
* @throws ServiceException
*/
protected JSONObject getParamGeometry(String name) throws ServiceException {
try {
return getParam(name).getJSONObject(GEOMETRY);
} catch (JSONException ex) {
throw new ServiceException("No geometry for " + name);
}
}
/**
* Get the full JSON parameter record.
* @param name
* @return the JSON record.
*/
private JSONObject getParam(String name) throws ServiceException {
JSONObject p = getParamMap().get(name);
if (p == null) {
throw new ServiceException("Parameter not found: '" + name + "'");
}
return p;
}
/**
* Get a service resource file. Resources are defined as service
* annotations.
*
* @param id the id of the resource.
* @return the extracted file within the local file system.
* @throws ServiceException
* @see csip.annotations.Resource
*/
protected File getResourceFile(String id) throws ServiceException {
return Binaries.getResourceFile(getClass(), id);
}
/**
* Get an service executable from a resource definition. Resources are
* defined as service annotations.
*
* @param id the id of the resource
* @return the ProcessExecution for that executable
* @throws ServiceException
* @see csip.annotations.Resource
*/
protected Executable getResourceExe(String id) throws ServiceException {
return Binaries.getResourceExe0(getClass(), id, getWorkspaceDir(), LOG);
}
/**
* Get a JDBC connection from a resource definition.
*
* @param id the id of the resource
* @return the JDBC connection.
* @throws ServiceException
* @see csip.annotations.Resource
*/
protected Connection getResourceJDBC(String id) throws ServiceException {
return Binaries.getRessourceJDBC(getClass(), id, LOG);
}
//////////////////////////////////////////////////////////////////////// results
/**
* Provide a string as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, String val, String descr, String unit) {
results().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Provide a string as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, String val, String descr) {
results().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Provide a string as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, String val) {
results().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Provide an int as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, int val, String descr, String unit) {
results().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Provide an int as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, int val, String descr) {
results().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Provide an int as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, int val) {
results().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Provide a generic object as a result. Supports returning a JSONObject.
* @param val the value to store
* @deprecated
*/
@Deprecated
protected void putResult(Object val) {
results().put(val);
}
/**
* Provide a double as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, double val, String descr, String unit) {
results().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Provide a double as a result.
* @param name the result name
* @param val the value to store
* @param descr
*/
protected void putResult(String name, double val, String descr) {
results().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Provide a double as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, double val) {
results().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Provide a boolean as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, boolean val, String descr, String unit) {
results().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Provide a boolean as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, boolean val, String descr) {
results().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Provide a boolean as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, boolean val) {
results().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Provide an Object as a result.
* @param name the result name
* @param val the value to store
* @param descr the description
*/
protected void putResult(String name, Object val, String descr) {
results().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Provide a JSONObject as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, Object val) {
results().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Provide a boolean array as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, boolean[] val, String descr, String unit) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, unit, descr));
}
/**
* Provide a boolean array as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, boolean[] val, String descr) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, descr));
}
/**
* Provide a boolean array as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, boolean[] val) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, null));
}
/**
* Provide a double array as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, double[] val, String descr, String unit) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, unit, descr));
}
/**
* Provide a double array as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, double[] val, String descr) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, descr));
}
/**
* Provide a double array as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, double[] val) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, null));
}
/**
* Provide a int array as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, int[] val, String descr, String unit) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, unit, descr));
}
/**
* Provide a int array as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, int[] val, String descr) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, descr));
}
/**
* Provide a int array as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, int[] val) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, null));
}
/**
* Provide a long array as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, long[] val, String descr, String unit) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, unit, descr));
}
/**
* Provide a long array as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, long[] val, String descr) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, descr));
}
/**
* Provide a long array as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, long[] val) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, null));
}
/**
* Provide a String array as a result.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putResult(String name, String[] val, String descr, String unit) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, unit, descr));
}
/**
* Provide a String array as a result.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putResult(String name, String[] val, String descr) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, descr));
}
/**
* Provide a String array as a result.
* @param name the result name
* @param val the value to store
*/
protected void putResult(String name, String[] val) {
JSONArray val_ = JSONUtils.toArray(val);
results().put(JSONUtils.dataUnitDesc(name, val_, null, null));
}
/**
* Provide a file as a result. If the files represents a folder, it gets
* added to the result as zip file.
*
* @param file the file to add as result.
*/
protected void putResult(File file) {
if (file == null || !file.exists() || !file.canRead()) {
throw new IllegalArgumentException("Cannot acces File/Folder: " + file);
}
if (file.isDirectory()) {
try {
// can only add zipped folder as output.
file = ZipFiles.zip(file);
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
return;
}
}
fresults().add(file);
}
/**
* Provide a file with description as a result.
* @param file
* @param descr
*/
protected void putResult(File file, String descr) {
putResult(file);
fdesc().put(file, descr);
}
/**
* Provide multiple files as a result.
* @param files the files to add as a result
*/
protected void putResult(File... files) {
for (File file : files) {
putResult(file);
}
}
///////////////////////////////////////////////////////////////////////// report
/**
* Put a String value into a report.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putReport(String name, String val, String descr, String unit) {
reportData().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Put a String value into a report.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putReport(String name, String val, String descr) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Put a String value into a report.
* @param name the result name
* @param val the value to store
*/
protected void putReport(String name, String val) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Put a int value into a report.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putReport(String name, int val, String descr, String unit) {
reportData().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Put a int value into a report.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putReport(String name, int val, String descr) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Put a int value into a report.
* @param name the result name
* @param val the value to store
*/
protected void putReport(String name, int val) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Put a double value into a report.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putReport(String name, double val, String descr, String unit) {
reportData().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Put a double value into a report.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putReport(String name, double val, String descr) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Put a double value into a report.
* @param name the result name
* @param val the value to store
*/
protected void putReport(String name, double val) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Put a boolean value into a report.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putReport(String name, boolean val, String descr, String unit) {
reportData().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Put a boolean value into a report.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putReport(String name, boolean val, String descr) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Put a boolean value into a report.
* @param name the result name
* @param val the value to store
*/
protected void putReport(String name, boolean val) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Put a JSONObject value into a report.
* @param name the result name
* @param val the value to store
* @param unit the physical unit
* @param descr a description
*/
protected void putReport(String name, Object val, String descr, String unit) {
reportData().put(JSONUtils.dataUnitDesc(name, val, unit, descr));
}
/**
* Put a JSONObject value into a report.
* @param name the result name
* @param val the value to store
* @param descr a description
*/
protected void putReport(String name, Object val, String descr) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, descr));
}
/**
* Put a JSONObject value into a report.
* @param name the result name
* @param val the value to store
*/
protected void putReport(String name, Object val) {
reportData().put(JSONUtils.dataUnitDesc(name, val, null, null));
}
/**
* Put a File into a report. If the argument is a folder, it gets zipped and
* put into the report as zipped file.
*
* @param file the file to report
*/
protected void putReport(File file) {
if (file == null || !file.exists() || !file.canRead()) {
throw new IllegalArgumentException("Cannot acces File/Folder: " + file);
}
if (file.isDirectory()) {
try {
// can only add zipped folder as report.
file = ZipFiles.zip(file);
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
return;
}
}
freports().add(file);
}
/**
* Put a File into a report.
* @param file the file
* @param descr a description
*/
protected void putReport(File file, String descr) {
putReport(file);
fdesc().put(file, descr);
}
/**
* Put Files into a report.
* @param files the files to report
*/
protected void putReport(File... files) {
for (File file : files) {
putReport(file);
}
}
///////////////////////////////////////////////////////////////////////private
private void doCreateReport(JSONObject meta) throws Exception {
JSONArray report = createReport();
if (report == null) {
report = rep;
}
if (report != null) {
if (frep != null) {
File[] reportfiles = frep.toArray(new File[0]);
annotateResults(report, reportfiles);
}
// put an flag into the metainfo to indicate report
// availability
meta.put("report", true);
JSONObject r = new JSONObject();
r.put(KEY_METAINFO, meta);
r.put(KEY_REPORT, report);
FileUtils.writeStringToFile(new File(getResultsDir(), REPORT_FILE), r.toString(2));
if (LOG.isLoggable(Level.INFO)) {
LOG.info("created report : " + new File(getResultsDir(), REPORT_FILE));
}
}
}
private void processResults(File[] resultfiles) throws IOException {
File wsDir = getWorkspaceDir();
File resultDir = getResultsDir();
for (File sfile : resultfiles) {
if (!sfile.exists()) {
sfile = new File(wsDir, sfile.toString());
if (!sfile.exists()) {
throw new IOException("Result file not found: " + sfile);
}
}
if (!sfile.canRead()) {
throw new IOException("Cannot read file: " + sfile);
}
if (LOG.isLoggable(Level.INFO)) {
LOG.info("Copy result" + sfile.toString() + " to " + resultDir);
}
FileUtils.copyFileToDirectory(sfile, resultDir);
}
}
private void annotateResults(JSONArray results, File[] files) throws Exception {
if (files == null || files.length == 0) {
return;
}
URI cb = Services.toPublicURL(getCodebase());
String url = cb.toString();
URIBuilder b = new URIBuilder();
for (File f : files) {
String fn = f.getName();
fn = b.setPath(fn).build().toString(); // proper url encoding.
String descr = fdesc().get(f);
results.put(JSONUtils.dataDesc(fn, url + "q/" + suid + "/" + fn, descr));
}
}
private JSONObject getFailedMetaInfo() {
try {
JSONObject metainfo_clone = (metainfo == null)
? new JSONObject() : JSONUtils.clone(metainfo);
metainfo_clone.put(KEY_STATUS, FAILED);
metainfo_clone.put(KEY_SUUID, suid);
metainfo_clone.put(KEY_TSTAMP, Dates.nowISO(tz));
metainfo_clone.put(KEY_SERVICE_URL, getRequestURL());
metainfo_clone.put(KEY_CLOUD_NODE, Services.LOCAL_IP_ADDR);
metainfo_clone.put(KEY_REQ_IP, getRemoteAddr());
String reqContext = getRequestContext().substring(1);
String v = Config.getString(reqContext + ".version");
if (v != null) {
metainfo_clone.put(reqContext + ".version", v);
}
metainfo_clone.put(CSIP_VERSION, Config.getString(CSIP_VERSION));
return metainfo_clone;
} catch (JSONException ex) {
LOG.log(Level.SEVERE, null, ex);
}
return null;
}
//////////////////////////////////////////////////////////////////// HTTP
/**
* Describe the service as JSON. (Service endpoint only)
* @return The service signature as JSON
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public final String describeJSON(@Context UriInfo uriInfo) {
LOG.log(Level.INFO, "HTTP/GET {0}", uriInfo.getRequestUri().toString());
LOG.log(Level.INFO, " Request Parameter template for " + getClass());
Resource[] resource = Binaries.getResourcesByType(getClass(), ResourceType.OMS_COMP);
if (resource.length > 0) {
try {
Class<?> cl = getClass();
if (!resource[0].file().isEmpty()) {
String classname = resource[0].file();
cl = Thread.currentThread().getContextClassLoader().loadClass(classname);
}
Object comp = cl.newInstance();
OMSComponentMapper cm = new OMSComponentMapper(comp);
return cm.getInputs().toString(4);
} catch (Exception ex) {
LOG.log(Level.WARNING, null, ex);
return JSONUtils.newRequest().toString();
}
}
String classname = '/' + getClass().getName().replace('.', '/');
try {
LOG.info("Search " + classname + "Req.json");
InputStream is = getClass().getResourceAsStream(classname + "Req.json");
if (is == null) {
LOG.info("Search " + classname + ".json");
is = getClass().getResourceAsStream(classname + ".json");
if (is == null) {
LOG.info("Return empty request.");
return JSONUtils.newRequest().toString(2);
}
}
return new JSONObject(IOUtils.toString(is)).toString(2);
} catch (IOException | JSONException ex) {
LOG.log(Level.WARNING, null, ex);
LOG.info("Return empty request.");
return JSONUtils.newRequest().toString();
}
}
/**
* Service Handler for non-multipart requests. There are no form parameter,
* everything is in the body. (Service endpoint only)
* @param uriInfo The UriInfo context
* @param httpReq tye servlet request
* @param requestStr the request string
* @return the JSON response of the service.
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public final String execute(@Context UriInfo uriInfo, @Context HttpServletRequest httpReq, String requestStr) {
LOG.log(Level.INFO, "HTTP/POST {0}", uriInfo.getRequestUri().toString());
req_remoteIp = httpReq.getHeader("X-Forwarded-For");
if (req_remoteIp == null) {
req_remoteIp = httpReq.getRemoteAddr();
}
req_host = httpReq.getRemoteHost();
req_url = httpReq.getRequestURL().toString();
req_context = httpReq.getContextPath();
req_scheme = httpReq.getScheme();
if (requestStr == null) {
return JSONUtils.error("Null JSON Request.").toString();
}
if (start == null) {
start = new Date();
processOptions();
state = getState();
}
if (LOG.isLoggable(Level.INFO)) {
LOG.info("path: " + getServicePath());
LOG.info("from: " + httpReq.getRemoteAddr() + "," + httpReq.getRemoteHost() + "," + httpReq.getRemoteUser());
int max = Config.getInt(CSIP_LOGGING_STRMAX, -1);
if (max > 0) {
int len = Math.min(max, requestStr.length());
LOG.info("request: " + requestStr.substring(0, len) + " ... (truncated)");
} else {
LOG.info("request: " + requestStr);
}
LOG.info("request url: " + httpReq.getRequestURL().toString());
LOG.info("context: " + httpReq.getContextPath());
LOG.info("x-forwarded-for:" + httpReq.getHeader("X-Forwarded-For"));
}
JSONObject response = null;
try {
try {
request = new JSONObject(requestStr);
} catch (JSONException E) {
return JSONUtils.error("Malformed JSON Request.").toString();
}
// get parameter and meta info.
param = request.getJSONArray(KEY_PARAMETER);
if (request.has(KEY_METAINFO)) {
metainfo = request.getJSONObject(KEY_METAINFO);
} else {
metainfo = new JSONObject();
}
FileUtils.writeStringToFile(new File(getResultsDir(), REQUEST_FILE), request.toString(2).replace("\\/", "/"));
// extract all Ressources
Binaries.extractAllResources(getClass(), LOG);
// Result store handling.
ResultStore rs = Config.getResultStore();
digest = rs.getDigest(getServicePath() + "-" + requestStr);
// not null if the ResultStorage implementation supports storage.
if (digest != null) {
// the client can overwrite and refresh the request.
if (!metainfo.optBoolean("rs_skip", false)) {
String result = rs.getResult(digest);
if (result != null) {
// it's in the store.
JSONObject metainfo_clone = JSONUtils.clone(metainfo);
// generate response.
metainfo_clone.put(KEY_STATUS, FINISHED);
metainfo_clone.put(KEY_SUUID, suid);
metainfo_clone.put(KEY_TSTAMP, Dates.nowISO(tz));
metainfo_clone.put(KEY_SERVICE_URL, getRequestURL());
metainfo_clone.put(KEY_CPU_TIME, Dates.diffInMillis(start, new Date()));
metainfo_clone.put("rs_digest", digest);
DateFormat df = Dates.newISOFormat(tz);
metainfo_clone.put(KEY_EXPIRATION_DATE, df.format(Dates.futureDate(getKeepResults())));
response = JSONUtils.newResponse(request, new JSONArray(result), metainfo_clone);
FileUtils.writeStringToFile(new File(getResultsDir(), RESPONSE_FILE), response.toString(2).replace("\\/", "/"));
return response.toString(2).replace("\\/", "/");
}
}
}
paramMap = JSONUtils.preprocess(param);
// add the attachmed inputs to it
if (inputs != null && inputs.length > 0) {
metainfo.put("attachments", "\"" + Arrays.toString(inputs) + "\"");
}
// handleCache(metainfo);
tz = JSONUtils.getJSONString(metainfo, KEY_TZ, Config.getString(CSIP_TIMEZONE));
if (LOG.isLoggable(Level.INFO)) {
LOG.info("timezone: " + tz);
}
if (metainfo.has(KEY_PARAMETERSETS)) {
// ensemble run
response = new Callable<JSONObject>() {
String path = getServicePath();
@Override
public JSONObject call() throws Exception {
// map the request to callables
List<Callable<JSONObject>> ens = Services.mapEnsemble(request, path);
if (ens != null) {
// execute it
List<Future<JSONObject>> results = Services.runEnsemble(ens);
// reduce results
return Services.reduceEnsemble(results, request);
} else {
return JSONUtils.newError(getFailedMetaInfo(), param, new ServiceException("Not an ensemble."));
}
}
}.call();
} else {
// single run:
// step 1 preprocess input
// preprocess();
serviceError = preProcess0();
if (serviceError != null) {
throw serviceError;
}
// step 2 create the model
Callable<Throwable> model = createCallable();
// Callable<Object> model = () -> {
// return process0();
// };
mt = new Task(model);
if (metainfo.has(KEY_MODE) && metainfo.getString(KEY_MODE).equals(ASYNC)) {
// async call
JSONObject metainfo_clone = JSONUtils.clone(metainfo);
// Put polling info in obj before starting!
if (getNextPoll() != -1) {
metainfo_clone.put(KEY_NEXT_POLL, getNextPoll());
}
if (getFirstPoll() != -1) {
metainfo_clone.put(KEY_FIRST_POLL, getFirstPoll());
}
// generate response.
metainfo_clone.put(KEY_STATUS, SUBMITTED);
metainfo_clone.put(KEY_SUUID, suid);
metainfo_clone.put(KEY_TSTAMP, Dates.nowISO(tz));
metainfo_clone.put(KEY_SERVICE_URL, getRequestURL());
// done, there is the response
response = JSONUtils.newResponse(request, null, metainfo_clone);
if (LOG.isLoggable(Level.INFO)) {
LOG.info("async run :" + response);
}
// start the async call as the very last thing before returning
mt.start();
} else {
// sync call
mt.run();
response = new JSONObject(FileUtils.readFileToString(new File(getResultsDir(), RESPONSE_FILE)));
}
}
} catch (Throwable T) {
LOG.log(Level.SEVERE, "ERROR:", T);
response = JSONUtils.newError(getFailedMetaInfo(), param, T);
}
LOG.close();
try {
return response.toString(2).replace("\\/", "/");
} catch (JSONException E) {
return response.toString().replace("\\/", "/");
}
}
/**
* Handler for model services. Multi-part handling. (Service endpoint only)
* @param uriInfo the context info
* @param httpReq the servlet request
* @param multipart multi part input.
*
* @return the JSON response as String.
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
public final String execute(@Context UriInfo uriInfo, @Context HttpServletRequest httpReq, FormDataMultiPart multipart) {
LOG.log(Level.INFO, "HTTP/POST {0}", uriInfo.getRequestUri().toString());
processOptions();
start = new Date();
String response = null;
try {
if (multipart == null || multipart.getBodyParts() == null || multipart.getBodyParts().isEmpty()) {
throw new ServiceException("Missing JSON request and/or files");
}
Map<String, FormDataParameter> m = Services.getFormParameter(multipart.getBodyParts());
File ws = getWorkspaceDir();
// copy all file - file9 to workspace.
inputs = Services.copyAndExtract(LOG, ws, m, unpack);
String requestStr = null;
// get param JSON
FormDataParameter fdParam = m.get(FORM_PARAM);
if (fdParam == null && !m.isEmpty()) {
// only files are attached, no json
requestStr = JSONUtils.newRequest().toString();
if (LOG.isLoggable(Level.INFO)) {
LOG.info("creating empty request string");
}
// throw new ServiceException("Missing JSON request.");
} else if (fdParam.getFilename() == null) {
// direct passing
requestStr = fdParam.getValue();
} else {
if (ws == null) {
throw new ServiceException("Illegal service configuration. missing simulation dir.");
}
File paramFile = new File(ws, fdParam.getFilename());
if (!paramFile.exists()) {
throw new ServiceException("Missing JSON request file.");
}
requestStr = FileUtils.readFileToString(paramFile);
}
// proxy to the regular call.
response = execute(uriInfo, httpReq, requestStr);
} catch (Throwable T) {
LOG.log(Level.SEVERE, "ERROR:", T);
response = JSONUtils.newError(getFailedMetaInfo(), param, T).toString();
}
// Let's not catch every exception so we have hope of finding the bug!
LOG.close();
return response.replace("\\/", "/");
}
/**
* Set the progress as a string message. Call this message during process()
* to indicate progress for long running models. If the service is called
* asynchronously the message will be reported in the metainfo part of the
* rest call as the 'progress' entry.
*
* @param progress a meaningful message
* @throws ServiceException
*/
protected void setProgress(String progress) throws ServiceException {
this.progress = progress;
mt.setRunningStatus();
}
/**
* Set the progress as a numerical value (0..100)
* @param progress a value between 0 and 100;
* @throws ServiceException
*/
protected void setProgress(int progress) throws ServiceException {
if (progress < 0 || progress > 100) {
throw new ServiceException("invalid progress: " + progress);
}
setProgress(Integer.toString(progress));
}
long getKeepResults() {
return Dates.getDurationSec("csip.session.ttl");
}
/**
* Model execution Task.
*
*/
public final class Task extends Thread {
static final long ONE_DAY = 60 * 60 * 24 * 1000; // 1 day in milli seconds, max time for a running job to be accessible.
//
FutureTask<Throwable> task;
String status = UNKNOWN;
Timer snapshot;
public Task(Callable<Throwable> call) {
task = new FutureTask<>(call);
}
@Override
public void run() {
ExecutorService es = Config.getExecutorService();
File[] resultfiles = null;
try {
es.submit(task);
Config.getModelTasks().add(this);
setRunningStatus();
// running from here on.
long sec = Dates.getDurationSec(CSIP_SNAPSHOT, -1);
if (sec > 0) {
if (Config.isArchiveEnabled()) {
snapshot = new Timer("timer-" + getSUID());
snapshot.scheduleAtFixedRate(new TimerTask() {
long dur = -1;
@Override
public void run() {
try {
if (sec > dur) {
long start = System.currentTimeMillis();
LOG.info("taking workspace snapshot ...");
ModelSession ms = Config.getSessionStore().getSession(suid);
File snapshotZip = zipWorkspace();
DateFormat df = Dates.newISOFormat(tz);
Date now = new Date();
Date expDate = Dates.futureDate(now, 31536000); // 1 year expiration
ModelArchive ma = new ModelArchive(df.format(now), df.format(expDate), getRequestURL(), ms.getStatus(), ms.getReqIP());
ArchiveStore as = Config.getArchiveStore();
if (as.hasArchive(suid)) {
as.removeArchive(suid);
}
as.archiveSession(suid, ma, snapshotZip);
FileUtils.deleteQuietly(snapshotZip);
long end = System.currentTimeMillis();
dur = (end - start) / 1000;
LOG.info("snapshot done in " + dur + " seconds.");
} else {
LOG.info("skipped snapshot: " + dur + " - " + sec);
}
} catch (Exception ex) {
Logger.getLogger(ModelDataService.class.getName()).log(Level.SEVERE, null, ex);
}
}
}, sec * 1000, sec * 1000);
}
}
// waiting here.
serviceError = task.get(timeout, TimeUnit.SECONDS);
if (serviceError == null) {
// step 3
// resultfiles = postprocess();
serviceError = postProcess0();
if (serviceError == null) {
// step 4
JSONArray results = createResults();
if (results == null) {
results = results();
}
if (resultfiles == null) {
resultfiles = fresults().toArray(new File[0]);
}
// automatically annotate the output if there are files being returned.
annotateResults(results, resultfiles);
JSONObject meta = setFinishedStatus(results);
// step 5 create a report (if supported)
doCreateReport(meta);
// done here
if (snapshot != null) {
snapshot.cancel();
}
}
}
if (serviceError != null) {
setFailedStatus(serviceError);
}
} catch (TimeoutException E) {
LOG.log(Level.INFO, "service: " + getServicePath() + " timed out after " + timeout + " seconds. service cancelled.");
setCancelledStatus();
} catch (CancellationException E) {
LOG.log(Level.INFO, "cancelled.");
setCancelledStatus();
} catch (Exception e) {
LOG.log(Level.SEVERE, null, e);
setFailedStatus(e);
} finally {
// manage exporation action
try {
final ModelSession ms = Config.getSessionStore().getSession(suid);
final String[] inputs = ms.getAttachments();
final File[] resf = resultfiles;
if (resf != null) {
processResults(resf);
}
if (frep != null) {
File[] repf = frep.toArray(new File[0]);
processResults(repf);
}
// archive management
new Thread(() -> {
if (Config.isArchiveEnabled()) {
if ((Config.getBoolean(CSIP_ARCHIVE_FAILEDONLY) && serviceError != null) // only archive if failed
|| !Config.getBoolean(CSIP_ARCHIVE_FAILEDONLY)) { // always archive
try {
long st = System.currentTimeMillis();
// close log before archiving.
LOG.close();
File archive = zipWorkspace();
// move it from session store to archive store.
// turn session into archive
DateFormat df = Dates.newISOFormat(tz);
Date now = new Date();
Date expDate = Dates.futureDate(now, Dates.getDurationSec("csip.archive.ttl"));
ModelArchive ma = new ModelArchive(df.format(now), df.format(expDate), getRequestURL(), ms.getStatus(), ms.getReqIP());
ArchiveStore as = Config.getArchiveStore();
if (as.hasArchive(suid)) {
as.removeArchive(suid);
}
as.archiveSession(suid, ma, archive);
FileUtils.deleteQuietly(archive);
long en = System.currentTimeMillis();
LOG.info("Archived " + suid + " in " + (en - st) + " ms.");
// Config.getAccessLogStore().log(suid, ms.getService(), ms.getReqIP(), Services.LOCAL_IP_ADDR, ms.getTstamp(), "Archived", -1);
} catch (Exception ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
}
// remove the workspace right away
// keep the results, let the Sweeper remove it after ttl
if (!Config.getBoolean(CSIP_KEEPWORKSPACE, false)) {
FileUtils.deleteQuietly(getWorkspaceDir());
}
// separate therad
Sweeper r = new Sweeper(hasResultsDir() ? getResultsDir() : null, suid);
long keepResults = getKeepResults();
if (ms.getStatus().equals(FAILED)) {
keepResults = Dates.getDurationSec("csip.session.ttl.failed");
} else if (ms.getStatus().equals(CANCELED)) {
keepResults = Dates.getDurationSec("csip.session.ttl.cancelled");
}
if (keepResults > 0) {
Config.getTimer().schedule(r, keepResults * 1000);
} else {
r.run();
}
}).start();
} catch (Exception ex) {
LOG.log(Level.SEVERE, null, ex);
}
LOG.close(); // this might already being closed if archived.
// remove the running session.
Config.getModelTasks().remove(this);
}
}
File zipWorkspace() throws IOException {
// copy back the files to the workspace to make them
// a part of the archive
File req = new File(getResultsDir(), REQUEST_FILE);
if (req.exists()) {
FileUtils.copyFileToDirectory(req, getWorkspaceDir());
}
File res = new File(getResultsDir(), RESPONSE_FILE);
if (res.exists()) {
FileUtils.copyFileToDirectory(res, getWorkspaceDir());
}
File log = new File(getResultsDir(), LOG_FILE);
if (log.exists()) {
FileUtils.copyFileToDirectory(log, getWorkspaceDir());
}
File archive = ZipFiles.zip(getWorkspaceDir());
return archive;
}
boolean cancel() {
return task.cancel(true);
}
ModelDataService getService() {
return ModelDataService.this;
}
@Override
public String toString() {
return "\n[" + suid + " - " + status + " - " + start.toString() + "]";
}
// status management.
private void store(JSONObject request, JSONObject metainfo, JSONArray results) {
try {
JSONObject response = JSONUtils.newResponse(request, results, metainfo);
File responseFile = new File(getResultsDir(), RESPONSE_FILE);
Lock l = Config.wsFileLocks.get(responseFile, (File t) -> new ReentrantLock());
l.lock();
try {
FileUtils.writeStringToFile(responseFile,
response.toString(2).replace("\\/", "/"));
} finally {
l.unlock();
}
String _status = metainfo.getString(KEY_STATUS);
String tstamp = metainfo.getString(KEY_TSTAMP);
String exp_date = "";
if (metainfo.has(KEY_EXPIRATION_DATE)) {
exp_date = metainfo.getString(KEY_EXPIRATION_DATE);
}
String cputime = "";
if (metainfo.has(KEY_CPU_TIME)) {
cputime = metainfo.getString(KEY_CPU_TIME);
}
boolean hasReport = metainfo.has("report") && metainfo.getBoolean("report");
ModelSession ms = new ModelSession(tstamp, exp_date, getServicePath(), _status,
Services.LOCAL_IP_ADDR, cputime, getRemoteAddr(), inputs, hasReport, progress);
Config.getSessionStore().setSession(suid, ms);
} catch (Exception ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
private JSONObject updateMetadata(String status) {
this.status = status;
JSONObject metainfo = getMetainfo();
try {
metainfo.put(KEY_STATUS, status);
metainfo.put(KEY_SUUID, suid);
metainfo.put(KEY_CLOUD_NODE, Services.LOCAL_IP_ADDR);
metainfo.put(KEY_TSTAMP, Dates.newISOFormat(tz).format(start));
metainfo.put(KEY_SERVICE_URL, getRequestURL());
metainfo.put(KEY_REQ_IP, getRemoteAddr());
String reqContext = getRequestContext().substring(1);
String v = Config.getString(reqContext + ".version");
if (v != null) {
metainfo.put(reqContext + ".version", v);
}
if (state != null) {
metainfo.put(KEY_STATE, state);
}
metainfo.put(CSIP_VERSION, Config.getString(CSIP_VERSION));
if (progress != null) {
metainfo.put(KEY_PROGRESS, progress);
}
} catch (JSONException ex) {
LOG.log(Level.SEVERE, null, ex);
}
return metainfo;
}
// empty request.
JSONObject empty_req = new JSONObject();
private void setRunningStatus() {
try {
JSONObject metainfo = updateMetadata(RUNNING);
store(empty_req, metainfo, null);
} catch (Exception ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
private JSONObject setFinishedStatus(JSONArray results) {
try {
// if digest != null will have a valid store.
if (digest != null) {
// only store the result if there are no input attachments
// and no output file is being produced.
if ((fres == null || fresults().isEmpty()) && getFileInputsCount() == 0) {
Config.getResultStore().putResult(digest, results.toString());
}
}
// only is progress is being touched, set it to 100%
JSONObject metainfo = updateMetadata(FINISHED);
metainfo.put(KEY_CPU_TIME, Dates.diffInMillis(start, new Date()));
DateFormat df = Dates.newISOFormat(tz);
Date expDate = Dates.futureDate(getKeepResults());
metainfo.put(KEY_EXPIRATION_DATE, df.format(expDate));
store(getRequest(), metainfo, results);
return metainfo;
} catch (JSONException ex) {
LOG.log(Level.SEVERE, null, ex);
return null;
}
}
private void setFailedStatus(Throwable err) {
String message = JSONUtils.getErrorMessage(err);
try {
JSONObject metainfo = updateMetadata(FAILED);
metainfo.put(KEY_CPU_TIME, Dates.diffInMillis(start, new Date()));
DateFormat df = Dates.newISOFormat(tz);
Date expDate = Dates.futureDate(getKeepResults());
metainfo.put(KEY_EXPIRATION_DATE, df.format(expDate));
metainfo.put(ERROR, message);
if (Config.getBoolean(CSIP_RESPONSE_STACKTRACE)) {
JSONArray trace = JSONUtils.getJSONStackTrace(err);
if (trace != null) {
metainfo.put("stacktrace", trace);
}
}
store(getRequest(), metainfo, null);
} catch (JSONException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
private void setCancelledStatus() {
try {
JSONObject metainfo = updateMetadata(CANCELED);
metainfo.put(KEY_CPU_TIME, Dates.diffInMillis(start, new Date()));
store(getRequest(), metainfo, null);
} catch (JSONException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
}
}