/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wps.hz;
import static org.geoserver.wps.hz.HazelcastStatusStore.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.geoserver.platform.resource.Resource;
import org.geoserver.platform.resource.Resource.Type;
import org.geoserver.platform.resource.ResourceStore;
import org.geotools.util.logging.Logging;
import org.springframework.beans.factory.DisposableBean;
import com.hazelcast.config.Config;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.XmlConfigBuilder;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
/**
* This class loads the Hazelcast configuration, making sure it contains the expected elements
*
* @author Andrea Aime - GeoSolutions
*/
public class HazelcastLoader implements DisposableBean {
private final static Logger LOGGER = Logging.getLogger(HazelcastLoader.class);
/** Name of the Hazelcast XML file to use */
public final static String HAZELCAST_NAME = "hazelcast.xml";
/** Hazelcast instance to pass to the {@link HazelcastCacheProvider} class */
private HazelcastInstance instance;
/**
* Loads a new {@link HazelcastInstance} from the data directory, and
*
* @param dd
* @throws IOException
*/
public HazelcastLoader(ResourceStore store) throws IOException {
// see if we have the hazelcast configuration ready, otherwise create one from the classpath
Resource resource = store.get(HAZELCAST_NAME);
if (resource.getType() == Type.UNDEFINED) {
try (OutputStream os = resource.out();
InputStream is = HazelcastLoader.class.getResourceAsStream(HAZELCAST_NAME)) {
IOUtils.copy(is, os);
}
}
try (InputStream is = resource.in()) {
Config config = new XmlConfigBuilder(is).build();
validateConfiguration(config);
instance = Hazelcast.newHazelcastInstance(config);
}
}
/**
* Starts with a given Hazelcast instance.
*
* @param dd
* @throws IOException
*/
HazelcastLoader(HazelcastInstance instance) {
this.instance = instance;
this.validateConfiguration(instance.getConfig());
}
/**
* Returns the Hazelcast instance to use
*
* @return Hazelcast instance if present or null
*/
public HazelcastInstance getInstance() {
return instance;
}
/**
* Validation for an input {@link Config} object provided. This method ensures that the input
* configuration contains the right map, and issues warning in case the map is configured as a
* cache instead of as a regular distributed map
*/
private void validateConfiguration(Config config) {
LOGGER.fine("Checking configuration");
if (config == null) {
throw new IllegalArgumentException("Hazelcast configuration should not be null");
}
// Check if the cache map is present
if (!config.getMapConfigs().containsKey(EXECUTION_STATUS_MAP)) {
throw new IllegalArgumentException(
"Hazelcast configuration is missing the status map, should be called: "
+ EXECUTION_STATUS_MAP);
}
// make some sanity checks on the map
MapConfig mapConfig = config.getMapConfig(EXECUTION_STATUS_MAP);
// Check size policy
if (mapConfig.getMaxSizeConfig().getSize() > 0) {
LOGGER.warning("The WPS status map " + EXECUTION_STATUS_MAP
+ " has a max size set, it should be unbounded so that no status is lost"
+ " before the configured timeout");
}
if (mapConfig.getEvictionPolicy() != MapConfig.DEFAULT_EVICTION_POLICY) {
LOGGER.warning("The WPS status map "
+ EXECUTION_STATUS_MAP
+ " has a eviction policy set, it should not automatically evict entries so that "
+ " no status is lost before the configured timeout");
}
}
@Override
public void destroy() throws Exception {
instance.shutdown();
}
}