package ee.telekom.workflow.core.common;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.annotation.PostConstruct;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.hazelcast.config.MulticastConfig;
/**
* Provides a common place to access configuration parameters.
* <p>
* Also provides default parameters for some of the values.
*
* @author Christian Klock
*/
@Component
public class WorkflowEngineConfiguration{
private static final String DEFAULT_HAZELCAST_INSTANCE_NAME = "telekomWorkflowEngineHazelcast";
private static final String DEFAULT_CLUSTER_MULTICAST_GROUP = MulticastConfig.DEFAULT_MULTICAST_GROUP;
private static final int DEFAULT_CLUSTER_MULTICAST_PORT = MulticastConfig.DEFAULT_MULTICAST_PORT;
private static final int DEFAULT_CLUSTER_MULTICAST_TTL = 0;
@Value("${database.workflowengine.schema:engine}")
private String schema;
@Value("${workflowengine.cluster.hazelcast.name}")
private String clusterHazelcastName;
@Value("${workflowengine.cluster.name}")
private String clusterName;
@Value("${workflowengine.cluster.multicast.group}")
private String clusterMulticastGroup;
@Value("${workflowengine.cluster.multicast.port}")
private String clusterMulticastPortText;
@Value("${workflowengine.cluster.multicast.ttl}")
private String clusterMulticastTtlText;
@Value("${workflowengine.node.name}")
private String nodeName;
private String hostName;
@Value("${workflowengine.heartbeat.intervalSeconds}")
private int heartbeatInterval;
@Value("${workflowengine.heartbeat.maximumPauseSeconds}")
private int heartbeatMaximumPauseSeconds;
@Value("${workflowengine.maximumNodeAssignementTimeSeconds}")
private int maximumNodeAssignmentTimeSeconds;
@Value("${workflowengine.producer.intervalSeconds}")
private int producerIntervalSeconds;
@Value("${workflowengine.consumer.threads}")
private int numberOfConsumerThreads;
@Value("${workflowengine.pluginApplicationContextFile}")
private String pluginApplicationContextFile;
@Value("${workflowengine.developmentMode}")
private boolean developmentMode;
@Value("${workflowengine.console.mapping.prefix:}")
private String consoleMappingPrefix;
@Value("${workflowengine.environment}")
private String environment;
@Value("${workflowengine.embeddedNavigationMode}")
private boolean embeddedNavigationMode;
@PostConstruct
public void init(){
hostName = getHostName();
}
/**
* Returns the PostgreSQL schema name + "." for workflow engine tables or an empty string if not configured. Used for constructing SQL queries.
*/
public String getSchema() {
return StringUtils.isNotBlank(schema) ? (schema + ".") : "";
}
/**
* This parameter is used as the Hazelcast instance bean name.
*/
public String getClusterHazelcastName(){
return StringUtils.isNotBlank(clusterHazelcastName) ? clusterHazelcastName : DEFAULT_HAZELCAST_INSTANCE_NAME;
}
/**
* This parameter is used as the Hazelcast cluster group name. It is also used to
* group workflow instances into groups. This leverages several clusters to run
* against one database (e.g. a cluster for every developer and a test instance and
* a prelive instance).
*/
public String getClusterName(){
return clusterName;
}
/**
* This parameter is used for Hazelcasts cluster member auto-detection
* and defaults to Hacelcasts multicast group default "224.2.2.3".
*/
public String getClusterMulticastGroup(){
return StringUtils.isNotBlank(clusterMulticastGroup) ? clusterMulticastGroup : DEFAULT_CLUSTER_MULTICAST_GROUP;
}
/**
* This parameter is used for Hazelcasts cluster member auto-detection
* and defaults to Hacelcasts multicast port default 54327.
*/
public int getClusterMulticastPort(){
return StringUtils.isNotBlank( clusterMulticastPortText ) ? Integer.valueOf( clusterMulticastPortText ) : DEFAULT_CLUSTER_MULTICAST_PORT;
}
/**
* This parameter is used for Hazelcasts cluster member auto-detection
* and defaults to 0. That means that multicast requests are restricted
* to the same host.
*/
public int getClusterMulticastTtl(){
return StringUtils.isNotBlank( clusterMulticastTtlText ) ? Integer.valueOf( clusterMulticastTtlText ) : DEFAULT_CLUSTER_MULTICAST_TTL;
}
/**
* This parameter is used as name when indicating which cluster node is
* currently executing a workflow instance.
*/
public String getNodeName(){
return StringUtils.isNotBlank(nodeName) ? nodeName : hostName;
}
/**
* Must be a value less than workflowengine.heartbeat.maximumPauseSeconds.<br/>
* Used as interval in seconds to run health check.
* Update node's heart beat field is to current date (see database table and field node.heartbeat)
* If master:
* Refresh locks expire time (sets the lock expire time to current time + workflowengine.heartbeat.maximumPauseSeconds)
* Find other nodes that are did not have a heartbeat for longer than workflowengine.heartbeat.maximumPauseSeconds and mark their status as failed
* If slave: Test whether lock has expired and attempt to acquire it
* If master: Run recovery
*/
public int getHeartbeatInterval(){
return heartbeatInterval;
}
/**
* Must be a value greater than workflowengine.heartbeat.intervalSeconds.
* Used as interval in seconds to declare a node as FAILED if it is in ENALBED
* state but did not have a heartbeat in the given interval
* that the master lock is valid (afterwards it expires)
*
* @return
*/
public int getHeartbeatMaximumPauseSeconds(){
return heartbeatMaximumPauseSeconds;
}
/**
* The maximum time a consumer is granted to update a workflow instance's
* node_name field after taking a work unit from the queue.
*/
public int getMaximumNodeAssignmentTimeSeconds(){
return maximumNodeAssignmentTimeSeconds;
}
/**
* The interval in seconds after which the poller attempts to find new work units.
*/
public int getProducerIntervalSeconds(){
return producerIntervalSeconds;
}
/**
* The number of consumer thread started when the engine starts.
*/
public int getNumberOfConsumerThreads(){
return numberOfConsumerThreads;
}
/**
* The Spring application context file for plugins. The context is started when
* the engine starts and closed when it shuts down. It is used to resolve beans
* by name during call and callAsync executions, find listeners to engine events,
* find workflow definitions.
*/
public String getPluginApplicationContextFile(){
return pluginApplicationContextFile;
}
/**
* Determines whether the engine is deployed in development mode (as opposed to production).
*/
public boolean isDevelopmentMode(){
return developmentMode;
}
public String getConsoleMappingPrefix() {
return consoleMappingPrefix != null ? consoleMappingPrefix : "";
}
/**
* Environment name, will be displayed (when not empty) in web console after application name
*/
public String getEnvironment(){
return environment;
}
/**
* Determines if the header logo and navigation links act as a stand-alone web app (default), or as embedded web screens.
*/
public boolean isEmbeddedNavigationMode() {
return embeddedNavigationMode;
}
private static String getHostName(){
try{
return InetAddress.getLocalHost().getHostName();
}
catch( UnknownHostException e ){
throw new RuntimeException( "Cannot determine host for this node", e );
}
}
}