Skip to content

Commit

Permalink
Fix #28 (#38)
Browse files Browse the repository at this point in the history
* Fix #28
Throw exception if instance with name cannot be found

* Remove unused 'debug' parameter
  • Loading branch information
emre-aydin committed Jan 12, 2017
1 parent ff07d03 commit 90955b2
Show file tree
Hide file tree
Showing 17 changed files with 506 additions and 188 deletions.
5 changes: 0 additions & 5 deletions README.md
Expand Up @@ -76,10 +76,6 @@ To set up Hazelcast Session Clustering:
<param-name>cookie-http-only</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>config-location</param-name>
<param-value>/WEB-INF/hazelcast.xml</param-value>
Expand Down Expand Up @@ -140,7 +136,6 @@ Following are the descriptions of parameters included in the above XML.
- `cookie-path`: Path of the session ID cookie. Its default value is based on the context path of the incoming request.
- `cookie-secure`: Specifies whether the cookie only be sent using a secure protocol. Its default value is false.
- `cookie-http-only`: Specifies whether the attribute `HttpOnly` cab be set on cookie. Its default value is false.
- `debug`: If set to true, the debugging feature is enabled. Its default value is false.
- `config-location`: Location of Hazelcast configuration. It can be specified as a servlet resource, classpath resource or as a URL. Its default value is `hazelcast-default.xml` or `hazelcast.xml` in the classpath.
- `instance-name`: Name of an existing Hazelcast instance, if you want to use it. Its default value is null.
- `use-client`: Specifies whether you want to connect to an existing cluster as a client. Its default value is false.
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/hazelcast/web/ClusteredSessionService.java
Expand Up @@ -122,6 +122,7 @@ private void ensureInstance() throws Exception {
}
} catch (Exception e) {
setFailedConnection(true);
LOGGER.warning("Cannot connect to Hazelcast server: " + e.getMessage());
if (LOGGER.isFinestEnabled()) {
LOGGER.finest("Cannot connect hazelcast server", e);
}
Expand All @@ -133,7 +134,7 @@ private void ensureInstance() throws Exception {
private void reconnectHZInstance() throws ServletException {
LOGGER.info("Retrying the connection!!");
lastConnectionTry = System.currentTimeMillis();
hazelcastInstance = HazelcastInstanceLoader.createInstance(this, filterConfig);
hazelcastInstance = HazelcastInstanceLoader.loadInstance(this, filterConfig);
clusterMap = hazelcastInstance.getMap(filterConfig.getMapName());
sss = (SerializationServiceSupport) hazelcastInstance;
setFailedConnection(false);
Expand Down
128 changes: 59 additions & 69 deletions src/main/java/com/hazelcast/web/HazelcastInstanceLoader.java
Expand Up @@ -20,26 +20,18 @@
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.client.config.XmlClientConfigBuilder;
import com.hazelcast.config.Config;
import com.hazelcast.config.InvalidConfigurationException;
import com.hazelcast.config.ListenerConfig;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.UrlXmlConfig;
import com.hazelcast.config.XmlConfigBuilder;
import com.hazelcast.core.DuplicateInstanceNameException;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.util.ExceptionUtil;
import com.hazelcast.web.listener.ClientLifecycleListener;
import com.hazelcast.web.listener.ServerLifecycleListener;

import javax.servlet.ServletException;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;

import static java.lang.String.format;

final class HazelcastInstanceLoader {

Expand All @@ -48,95 +40,93 @@ final class HazelcastInstanceLoader {
private HazelcastInstanceLoader() {
}

static HazelcastInstance createInstance(final ClusteredSessionService sessionService,
WebFilterConfig filterConfig) throws ServletException {

final String instanceName = filterConfig.getInstanceName();
URL configUrl = filterConfig.getConfigUrl();
int sessionTTLConfig = filterConfig.getSessionTtlSeconds();
static HazelcastInstance loadInstance(ClusteredSessionService sessionService, WebFilterConfig filterConfig)
throws ServletException {

if (filterConfig.isUseClient()) {
boolean isSticky = filterConfig.isStickySession();
return createClientInstance(sessionService, configUrl, instanceName, isSticky);
if (filterConfig.getInstanceName() != null) {
if (filterConfig.isUseClient()) {
return loadExistingClient(sessionService, filterConfig.getInstanceName());
} else {
return loadExistingInstance(sessionService, filterConfig.getInstanceName());
}
} else {
if (filterConfig.isUseClient()) {
return createClient(sessionService, filterConfig);
} else {
return createInstance(sessionService, filterConfig);
}
}
Config config = getServerConfig(filterConfig.getMapName(), configUrl, sessionTTLConfig);
return createHazelcastInstance(sessionService, instanceName, config);
}

private static Config getServerConfig(String mapName, URL configUrl, int sessionTTLConfig) throws ServletException {
private static HazelcastInstance createInstance(ClusteredSessionService sessionService, WebFilterConfig filterConfig)
throws ServletException {

LOGGER.info("Creating a new HazelcastInstance for session replication");

Config config;
if (configUrl == null) {
if (filterConfig.getConfigUrl() == null) {
config = new XmlConfigBuilder().build();
} else {
try {
config = new UrlXmlConfig(configUrl);
config = new UrlXmlConfig(filterConfig.getConfigUrl());
} catch (IOException e) {
throw new ServletException(e);
}
}
MapConfig mapConfig = config.getMapConfig(mapName);
try {
mapConfig.setMaxIdleSeconds(sessionTTLConfig);
} catch (NumberFormatException e) {
//noinspection ThrowableNotThrown
ExceptionUtil.rethrow(new InvalidConfigurationException("session-ttl-seconds must be a numeric value"));
}
return config;
}

private static HazelcastInstance createHazelcastInstance(ClusteredSessionService sessionService,
String instanceName, Config config) {
ListenerConfig listenerConfig = new ListenerConfig(new ServerLifecycleListener(sessionService));
config.addListenerConfig(listenerConfig);
if (!isEmpty(instanceName)) {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.info(format("getOrCreateHazelcastInstance for session replication, using name '%s'", instanceName));
}
config.setInstanceName(instanceName);
return Hazelcast.getOrCreateHazelcastInstance(config);
} else {
LOGGER.info("Creating a new HazelcastInstance for session replication");
return Hazelcast.newHazelcastInstance(config);
}
config.getMapConfig(filterConfig.getMapName()).setMaxIdleSeconds(filterConfig.getSessionTtlSeconds());
config.addListenerConfig(new ListenerConfig(new ServerLifecycleListener(sessionService)));

return Hazelcast.newHazelcastInstance(config);
}

private static HazelcastInstance createClientInstance(ClusteredSessionService sessionService,
URL configUrl, String instanceName,
boolean isSticky) throws ServletException {
LOGGER.warning("Creating HazelcastClient for session replication...");
private static HazelcastInstance createClient(ClusteredSessionService sessionService, WebFilterConfig filterConfig)
throws ServletException {

LOGGER.warning("Creating a new HazelcastClient for session replication...");
LOGGER.warning("make sure this client has access to an already running cluster...");

ClientConfig clientConfig;
if (configUrl == null) {
if (filterConfig.getConfigUrl() == null) {
clientConfig = new ClientConfig();
} else {
try {
clientConfig = new XmlClientConfigBuilder(configUrl).build();
clientConfig = new XmlClientConfigBuilder(filterConfig.getConfigUrl()).build();
} catch (IOException e) {
throw new ServletException(e);
throw new ServletException("Failed to load client config XML file [" + filterConfig.getConfigUrl()
+ "]:" + e.getMessage(), e);
}
}
if (isSticky) {
if (filterConfig.isStickySession()) {
clientConfig.getNetworkConfig().setConnectionAttemptLimit(1);
}
ListenerConfig listenerConfig = new ListenerConfig(new ClientLifecycleListener(sessionService));
clientConfig.addListenerConfig(listenerConfig);

if (!isEmpty(instanceName)) {
HazelcastInstance instance = HazelcastClient.getHazelcastClientByName(instanceName);
if (instance != null) {
return instance;
}
clientConfig.setInstanceName(instanceName);
try {
return HazelcastClient.newHazelcastClient(clientConfig);
} catch (DuplicateInstanceNameException e) {
return HazelcastClient.getHazelcastClientByName(instanceName);
}
}
clientConfig.addListenerConfig(new ListenerConfig(new ClientLifecycleListener(sessionService)));

return HazelcastClient.newHazelcastClient(clientConfig);
}

private static boolean isEmpty(String s) {
return s == null || s.trim().length() == 0;
private static HazelcastInstance loadExistingInstance(ClusteredSessionService sessionService, String instanceName)
throws ServletException {

LOGGER.info("Using existing Hazelcast instance with name [" + instanceName + "] for session replication");
HazelcastInstance instance = Hazelcast.getHazelcastInstanceByName(instanceName);
if (instance == null) {
throw new ServletException("Hazelcast instance with name [" + instanceName + "] could not be found.");
}
instance.getLifecycleService().addLifecycleListener(new ClientLifecycleListener(sessionService));
return instance;
}

private static HazelcastInstance loadExistingClient(ClusteredSessionService sessionService, String instanceName)
throws ServletException {

LOGGER.info("Using existing Hazelcast client instance with name [" + instanceName + "] for session replication");
HazelcastInstance client = HazelcastClient.getHazelcastClientByName(instanceName);
if (client == null) {
throw new ServletException("Hazelcast client instance with name [" + instanceName + "] could not be found.");
}
client.getLifecycleService().addLifecycleListener(new ClientLifecycleListener(sessionService));
return client;
}
}
112 changes: 75 additions & 37 deletions src/main/java/com/hazelcast/web/WebFilterConfig.java
Expand Up @@ -26,8 +26,10 @@
import javax.servlet.ServletContext;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
Expand All @@ -50,7 +52,6 @@ public final class WebFilterConfig {
private static final String SHUTDOWN_ON_DESTROY = "shutdown-on-destroy";
private static final String DEFERRED_WRITE = "deferred-write";
private static final String USE_REQUEST_PARAMETER = "use-request-parameter";
private static final String DEBUG = "debug";
private static final String TRANSIENT_ATTRIBUTES = "transient-attributes";

private static final String COOKIE_NAME = "cookie-name";
Expand All @@ -68,7 +69,6 @@ public final class WebFilterConfig {
private boolean shutdownOnDestroy;
private boolean deferredWrite;
private boolean useRequestParameter;
private boolean debug;
private Set<String> transientAttributes;
private String cookieName;
private String cookieDomain;
Expand All @@ -82,18 +82,7 @@ private WebFilterConfig() {
public static WebFilterConfig create(FilterConfig filterConfig, Properties properties) {
boolean useClient = getBoolean(filterConfig, properties, USE_CLIENT, false);

if (useClient) {
if (paramExists(filterConfig, properties, SESSION_TTL_CONFIG)) {
throw new InvalidConfigurationException(SESSION_TTL_CONFIG + " cannot be used with client mode.");
}
if (paramExists(filterConfig, properties, CONFIG_LOCATION)) {
throw new InvalidConfigurationException(CONFIG_LOCATION + " cannot be used with client mode.");
}
} else {
if (paramExists(filterConfig, properties, CLIENT_CONFIG_LOCATION)) {
throw new InvalidConfigurationException(CLIENT_CONFIG_LOCATION + " cannot be used with P2P mode.");
}
}
validateHazelcastConfigParameters(filterConfig, properties, useClient);

// Client mode parameters
String clientConfigLocation = getString(filterConfig, properties, CLIENT_CONFIG_LOCATION, null);
Expand All @@ -113,7 +102,6 @@ public static WebFilterConfig create(FilterConfig filterConfig, Properties prope
boolean shutdownOnDestroy = getBoolean(filterConfig, properties, SHUTDOWN_ON_DESTROY, true);
boolean deferredWrite = getBoolean(filterConfig, properties, DEFERRED_WRITE, false);
boolean useRequestParameter = getBoolean(filterConfig, properties, USE_REQUEST_PARAMETER, false);
boolean debug = getBoolean(filterConfig, properties, DEBUG, false);
Set<String> transientAttributes = getStringSet(filterConfig, properties, TRANSIENT_ATTRIBUTES);
String cookieName = getString(filterConfig, properties, COOKIE_NAME, "hazelcast.sessionId");
String cookieDomain = getString(filterConfig, properties, COOKIE_DOMAIN, null);
Expand All @@ -131,7 +119,6 @@ public static WebFilterConfig create(FilterConfig filterConfig, Properties prope
wfc.shutdownOnDestroy = shutdownOnDestroy;
wfc.deferredWrite = deferredWrite;
wfc.useRequestParameter = useRequestParameter;
wfc.debug = debug;
wfc.transientAttributes = transientAttributes;
wfc.cookieName = cookieName;
wfc.cookieDomain = cookieDomain;
Expand All @@ -141,17 +128,6 @@ public static WebFilterConfig create(FilterConfig filterConfig, Properties prope
return wfc;
}

private static URL validateAndGetConfigUrl(ServletContext ctx, boolean useClient, String configLocation,
String clientConfigLocation) {
if (!useClient && configLocation != null) {
return getConfigURL(ctx, configLocation);
} else if (useClient && clientConfigLocation != null) {
return getConfigURL(ctx, clientConfigLocation);
} else {
return null;
}
}

public boolean isUseClient() {
return useClient;
}
Expand Down Expand Up @@ -188,10 +164,6 @@ public boolean isUseRequestParameter() {
return useRequestParameter;
}

public boolean isDebug() {
return debug;
}

public Set<String> getTransientAttributes() {
return transientAttributes;
}
Expand Down Expand Up @@ -262,12 +234,7 @@ private static Set<String> getStringSet(FilterConfig filterConfig, Properties pr
}
}

private static boolean paramExists(FilterConfig filterConfig, Properties properties, String paramName) {
return filterConfig.getInitParameter(paramName) != null
|| (properties != null && properties.getProperty(paramName) != null);
}

private static URL getConfigURL(final ServletContext ctx, final String configLocation) {
private static URL getConfigUrl(final ServletContext ctx, final String configLocation) {
URL configUrl = null;
try {
configUrl = ctx.getResource(configLocation);
Expand All @@ -290,4 +257,75 @@ private static String getValue(FilterConfig filterConfig, Properties properties,
return filterConfig.getInitParameter(paramName);
}
}

private static URL validateAndGetConfigUrl(ServletContext ctx, boolean useClient, String configLocation,
String clientConfigLocation) {
if (!useClient && configLocation != null) {
return getConfigUrl(ctx, configLocation);
} else if (useClient && clientConfigLocation != null) {
return getConfigUrl(ctx, clientConfigLocation);
} else {
return null;
}
}

private static void validateHazelcastConfigParameters(FilterConfig filterConfig, Properties properties, boolean useClient) {
if (paramExists(filterConfig, properties, INSTANCE_NAME)) {
List<String> wrongParams = parametersExist(filterConfig, properties, SESSION_TTL_CONFIG,
CONFIG_LOCATION, CLIENT_CONFIG_LOCATION);

if (!wrongParams.isEmpty()) {
StringBuilder errorMsgBuilder = new StringBuilder("The following parameters cannot be used when "
+ INSTANCE_NAME + " is set to 'true' because an existing Hazelcast");
if (useClient) {
errorMsgBuilder.append("Client");
}
errorMsgBuilder.append(" instance is being used: [");
for (int i = 0; i < wrongParams.size(); i++) {
errorMsgBuilder.append(wrongParams.get(i));
if (i != wrongParams.size() - 1) {
errorMsgBuilder.append(", ");
}
}
errorMsgBuilder.append("]");
throw new InvalidConfigurationException(errorMsgBuilder.toString());
}
}

if (useClient) {
List<String> wrongParams = parametersExist(filterConfig, properties, SESSION_TTL_CONFIG, CONFIG_LOCATION);
if (!wrongParams.isEmpty()) {
StringBuilder errorMsgBuilder = new StringBuilder("The following parameters cannot be used when "
+ USE_CLIENT + " is set to 'true': [");
for (int i = 0; i < wrongParams.size(); i++) {
errorMsgBuilder.append(wrongParams.get(i));
if (i != wrongParams.size() - 1) {
errorMsgBuilder.append(", ");
}
}
errorMsgBuilder.append("]");
throw new InvalidConfigurationException(errorMsgBuilder.toString());
}
} else {
if (paramExists(filterConfig, properties, CLIENT_CONFIG_LOCATION)) {
throw new InvalidConfigurationException(CLIENT_CONFIG_LOCATION + " cannot be used with P2P mode.");
}
}
}

private static List<String> parametersExist(FilterConfig filterConfig, Properties properties,
String... parameterNames) {
ArrayList<String> parameters = new ArrayList<String>(parameterNames.length);
for (String pName : parameterNames) {
if (paramExists(filterConfig, properties, pName)) {
parameters.add(pName);
}
}
return parameters;
}

private static boolean paramExists(FilterConfig filterConfig, Properties properties, String paramName) {
return (filterConfig != null && filterConfig.getInitParameter(paramName) != null)
|| (properties != null && properties.getProperty(paramName) != null);
}
}

0 comments on commit 90955b2

Please sign in to comment.