/*
* Copyright 2015 Collective, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.collective.celos.servlet;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.collective.celos.*;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import com.collective.celos.database.StateDatabase;
import com.google.common.collect.ImmutableMap;
/**
* Superclass for all servlets that access the database.
*
* Serializes all database accesses with a lock.
*/
@SuppressWarnings("serial")
public abstract class AbstractServlet extends HttpServlet {
private static Logger LOGGER = Logger.getLogger(AbstractServlet.class);
public static final String SCHEDULER_ATTR = "celos.scheduler";
/**
* This lock serves to synchronize all operations.
*/
protected static final Object LOCK = new Object();
@Override
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
synchronized(LOCK) {
try {
super.service(req, res);
} catch(ServletException|IOException|RuntimeException e) {
LOGGER.error(e.getMessage(), e);
res.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getLocalizedMessage());
throw e;
}
}
}
protected ScheduledTime getRequestTime(HttpServletRequest req) {
String t = req.getParameter(CelosClient.TIME_PARAM);
if (t == null) {
return new ScheduledTime(DateTime.now(DateTimeZone.UTC));
} else {
return new ScheduledTime(t);
}
}
/*
* Scheduler cache
*
* Reading and evaluating the .js files takes a bit of time, so it is cached
* between servlet calls.
*
* The scheduler servlet uses createAndCacheScheduler(), which refreshes
* the cache once a minute, whereas all other servlets use, for performance,
* getOrCreateCachedScheduler() which usually retrieves the cached
* scheduler. The clear-cache servlet can be used during e.g. integration testing
* to reset the cache and force a reload of the configuration.
*/
private SchedulerConfiguration getSchedulerConfiguration() throws IOException {
String workflowConfigPath = Util.requireNonNull(getServletContext().getInitParameter(Constants.WORKFLOW_CONFIGURATION_PATH_ATTR));
String defaultsConfigPath = Util.requireNonNull(getServletContext().getInitParameter(Constants.DEFAULTS_CONFIGURATION_PATH_ATTR));
StateDatabase database = (StateDatabase) Util.requireNonNull(getServletContext().getAttribute(Constants.DATABASE));
Map<String, String> additionalVars = (Map<String, String>) getServletContext().getAttribute(Constants.ADDITIONAL_JS_VARIABLES);
if (additionalVars == null) {
additionalVars = ImmutableMap.of();
}
SchedulerConfiguration schedulerConfiguration = new SchedulerConfiguration(
new File(workflowConfigPath), new File(defaultsConfigPath), database, additionalVars
);
return schedulerConfiguration;
}
protected Scheduler createAndCacheScheduler() throws Exception {
SchedulerConfiguration schedulerConfiguration = getSchedulerConfiguration();
Scheduler sch = schedulerConfiguration.makeDefaultScheduler();
getServletContext().setAttribute(SCHEDULER_ATTR, sch);
return sch;
}
protected Scheduler getOrCreateCachedScheduler() throws Exception {
Scheduler sch = (Scheduler) getServletContext().getAttribute(SCHEDULER_ATTR);
if (sch == null) {
return createAndCacheScheduler();
} else {
return sch;
}
}
protected void clearSchedulerCache() {
getServletContext().removeAttribute(SCHEDULER_ATTR);
}
protected StateDatabase getStateDatabase() throws IOException {
return getSchedulerConfiguration().getStateDatabase();
}
}