Hazelcast client config fails if one of many servers down - java

I have this code where
hazelcastAddr is an array of URL strings.
ClientConfig config = new ClientConfig();
config.setProperty("hazelcast.logging.type", LOGGING_TYPE);
for (String hazelcastAddr : hazelcastAddrArray) {
LOG.trace("Hazelcast attempting to add network config for ip address <<{}>>.", hazelcastAddr);
config.getNetworkConfig().addAddress(hazelcastAddr);
}
return config;
hazelcastInstance = HazelcastClient.newHazelcastClient(config);
If hazelcastAddr gives four different URL Strings (for four different instances) and they are all currently up and running then things go as expected. However, if one (or two or three) are down then it throws an exception and fails to return an instance of the HazelcastClient. However, since it is able to connect to at least one it seems to me that it should still connect and the running instance(s) should be able to give it the current state of the system for it to work correctly.
Please update me on how to get this behaviour or if I am missing something and this should be the correct behaviour.
Thanks in advance.

Related

How do I initialize a CuratorFramework for a ZooKeeper cluster with dynamic size?

I just implemented a distibuted lock using Apache Curator und ZooKeeper in standalone mode.
I initialzed the CuratorFramework as follows:
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2182", retryPolicy);
Everything worked fine, so I tried to use ZooKeeper in cluster mode. I started three instances and initialzed the CuratorFramework as follows:
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2182,localhost:2182,localhost:2183", retryPolicy);
As you can see, I just added the addresses of the two new nodes.
So far so good.But how do I initialize the client, when I don't know the addresses of each node respectively the size of the cluster, because I want to scale it dynamically?
I could initialize it by only specifying the address of the first node which will always be started. But if that node goes down, Curator loses the connection to the whole cluster (I just tried it).
CuratorFrameworkFactory has a builder that allows you to specify an EnsembleProvider instead of a connectionString and to include an EnsembleTracker. This will keep your connectionString up to date, but you will need to persist the data somehow to ensure your application can find the ensemble when it restarts. I recommend implementing a decorating EnsembleProvider that encapsulates a FixedEnsembleProvider and writes the config to a properties file.
Example:
EnsembleProvider ensemble = new MyDecoratingEnsembleProvider(new FixedEnsembleProvider("localhost:2182", true));
CuratorFramework client = CuratorFrameworkFactory.builder()
.ensembleProvider(ensemble)
.retryPolicy(retryPolicy)
.ensembleTracker(true)
.build();
You should always know where your Zookeeper instances are. There's no way to connect to something when you don't know where it is - how could you?
If you can connect to any instance, you can get the configuration details and poll it regularly to keep your connection details up-to-date, perhaps?
maybe take a look at https://zookeeper.apache.org/doc/r3.5.5/zookeeperReconfig.html#ch_reconfig_rebalancing

Using Meek Transport

I am trying to integrate Meek in an Android application. There is a sample here that shows how to instantiate the transport:
https://github.com/guardianproject/AndroidPluggableTransports/blob/master/sample/src/main/java/info/pluggeabletransports/sample/SampleClientActivity.java
The question is what do I do from there. Assuming I have an application that uses OkHttp3. Is there a way to reconcile both and use OkHttp3 as underlying transport mechanism while the app only interacts with Okhttp3?
I am also quite conflicted on how to instantiate the transport and what each option means. In the link provided above, the transport is instantiate as follows:
private void initMeekTransport() {
new MeekTransport().register();
Properties options = new Properties();
String remoteAddress = "185.152.65.180:9001";// a public Tor guard to test
options.put(MeekTransport.OPTION_URL,"https://meek.azureedge.net/"); //the public Tor Meek endpoint
options.put(MeekTransport.OPTION_FRONT, "ajax.aspnetcdn.com"); //the domain fronting address to use
options.put(MeekTransport.OPTION_KEY, "97700DFE9F483596DDA6264C4D7DF7641E1E39CE"); //the key that is needed for this endpoint
init(DispatchConstants.PT_TRANSPORTS_MEEK, remoteAddress, options);
}
However, in the README (https://github.com/guardianproject/AndroidPluggableTransports), the suggested approach is:
Properties options = new Properties();
String bridgeAddress = "https://meek.actualdomain.com";
options.put(MeekTransport.OPTION_FRONT,"www.somefrontabledomain.com");
options.put(MeekTransport.OPTION_KEY,"18800CFE9F483596DDA6264C4D7DF7331E1E39CE");
init("meek", bridgeAddress, options);
Transport transport = Dispatcher.get().getTransport(this, PT_TRANSPORTS_MEEK, options);
if (transport != null)
{
Connection conn = transport.connect(bridgeAddress);
//now use the connection, either as a proxy, or to read and write bytes directly
if (conn.getLocalAddress() != null && conn.getLocalPort() != -1)
setSocksProxy (conn.getLocalAddress(), conn.getLocalPort());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("GET https://somewebsite.org/TheProject.html HTTP/1.0".getBytes());
conn.write(baos.toByteArray());
byte[] buffer = new byte[1024*64];
int read = conn.read(buffer,0,buffer.length);
String response = new String(buffer);
}
In the latter approach, the bridge address is passed to the init() method. In the first approach it is the remote address that is passed to the init() method while the bridge address is passed as option. Which one of these approaches is the right one?
Furthermore, I would appreciate some comments on OPTION_URL, OPTION_FRONT, and OPTION_KEY. Where does each of these pieces of information come from? If I do not want to use these default information, how do i go about setting up a "Meek endpoint" for instance to not use the default Tor one? Anything particular needs to be done on the CDN? How would I use Amazon or Google instead of aspnetcdn?
As you can see, I am fairly confused.
Thanks for your interest in this library. Unfortunately, we haven't made a formal release yet, and it is still quite early in its development.
However, we think that we can help still.
First, it should be made clear that the major cloud providers (Google, Amazon, Azure) that support domain fronting, are now very much against it. Thus, you might find some limitation in using any of those platforms, especially with a fronted domain that you do not control.
You can read about Tor and Signal's own struggle with this here: https://signal.org/blog/looking-back-on-the-front/ and https://blog.torproject.org/domain-fronting-critical-open-web
Now, that said, if you still want to proceed with domain fronting, and all you are using is HTTP/S, then you can do so, without using Meek at all. You simple need to set the "Host" header on your request to the actual domain you want to access, while the request itself using the fronted domain. It is actually quite simple.
You can read more here: https://www.bamsoftware.com/papers/fronting/#sec:introduction

How to bind variables into websocket route paths using Spark Web Framework?

I'm, trying to implement a websocket server using Spark (a java web framework). I'm using the version 2.3 that has added support for it.
There's some way to bind variables into route paths just like http routes?
e.g. /chat/:city
I want to create conversation channels among users. If it's possible, how can I make it work and how can I retrieve the variable?
Simply add ?userId=somekey to the end of path on your client side. Example would be to initialize your websocket path to Spark.websocket("/chat") (server-side obvi.) . Then have your client hit the URL with /chat?userId=blah. From the server side you'll receive a connection for the socket. From there simply grab the incoming URI from the socket connection and use the String userKey = session.getRemote().getQuery() method to pull of the field. May have to do a user.split("=")[1] to get the value
(stackoverflow's answer didn't worked for me, but pointed me in the right direction):
I managed to get the parameters this way:
#OnWebSocketConnect
void onConnect(Session sockSession) throws Exception {
Map<String, List<String>> params = sockSession.upgradeRequest.parameterMap;
if(params != null && params.containsKey("city")) {
// As the parameter's value is a List, we use 'get(0)'
String city = params.get("city").get(0);
...
}
...
}

SMTP/POP3 through proxy System.getProperties() vs new Properties()?

Im trying to get mail from a POP3 server through a proxy. Most "tutorials" suggest doing something like
Properties p = System.getProperties();
p.setProperty("proxySet", "true");//does this line even do anything?
p.setProperty("socksProxyHost", proxyHost);
p.setPorperty("socksProxyPort", proxyPort);
p.setProperty("socksProxyVersion", "5");//or 4 if you want to use 4
p.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
p.setProperty("mail.pop3.socketFactory.fallback", "false");//also not sure what it does
p.setProperty("mail.pop3.port", portOnHostYouWantToTalkTo);
p.setProperty("mail.pop3.socketFactory.port", portOnHostYouWantToTalkTo);
Session session = Session.getDefaultInstance(p, null);
//or session = Session.getInstance(p, null);
URLName urlName = new URLName(protocol, hostYouwantToTalkTo, portOnHostYouWantToTalkTo, null, mailbox, mailboxPassword);
Store store = session.getStore(urlName);
Now, if I do something like this I get an exception:
java.net.SocketException: Can't connect to SOCKS proxy:Connection timed out: connect.
My POP3 server does not log any connections, suggesting there is a proxy issue or an error in my code. I am using 73.29.157.190:29099 for now.
2) If, however, I do
Properties p = new Properties();
//all the same logic and stuff
Session = Session.getInstance(p, null);
My POP3 server logs a connection from localhost, and works properly, suggesting that I am NOT using a proxy to connect to it and everything else is fine.
My question is, why do "tutorials" use System.getProperties() and pass it to getInstance()? Every Session instance will keep a reference to System.properties. So, effectively every Session instance will be affected every time you try to create a new one or alter System.getProperties() in any way so you might as well reuse the same one.
Does javamail need something set in System.properties specifically and not the ones passed to Session?
Also, what parameters do you need to set in order to get javamail to use a proxy? What does System.properties have that makes it work unlike my new Properties? A link to a good tutorial or documentation that explains it would be greatly appreciated.
Thanks!
First, get rid of all the socket factory stuff, you don't need it.
Next, make sure you really have a SOCKS proxy and not just a web proxy. If you do, see this JavaMail FAQ entry.
Setting the System properties for a SOCKS proxy will cause all network connections from your program to go through the proxy server, which may not be what you want.

Remote JNDI lookup returning my own EJB

This is my first question at Stack Overflow, so feel free to tell me if I do something wrong :)
I'm working on a project involving EJB and JBoss 4.2.3.GA. In a point, we try to access every node of the cluster, locating an EJB and returning it.
This is the piece of code that does the JNDI lookup:
public static <I> I getCache(Class<I> i, String clusterNode) {
ServiceLocator serviceLocator = ServiceLocator.getInstance();
String jndi = serviceLocator.getRemoteJNDIName(i);
Properties props = new Properties();
props.setProperty(Context.PROVIDER_URL, "jnp://" + clusterNode + ":"
+ jndiPort);
props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming");
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
Object result = null;
try {
InitialContext ctx = new InitialContext(props);
result = ctx.lookup(jndi);
} catch (NamingException e) {
return null;
}
return (I) result;
}
Here:
clusterNode is a simple string with the IP address or the dns name of the node. E.g: "192.168.2.65" or "cluster1".
getRemoteJNDIName returns an String such as this: "MyEARName/MyEJBName/remote"
The problem is that when I call this method with, for example, "127.0.0.1" it works fine. Also, if I call it with an existing and working IP address where a server is up and running, it's OK too.
However if I call the method with a non-existing or non-working address or dns name, instead of throwing the NamingException, it returns the EJB in my own machine. Therefore, I don't know wether the node is up or not.
I guess there may be better ways to do it. I'd like to hear about them, but we cannot make "big" changes to the product due to it being in production for a few years by now.
That's it. Thank you in anticipation and best regards.
However if I call the method with a non-existing or non-working
address or dns name, instead of throwing the NamingException, it
returns the EJB in my own machine
I think this behavior can be explained if you have automatic naming discovery. When the Contex.PROVIDER_URL is not specified or the nodes in the list are not reachable (which is your case) the client is allowed to search in the network for available JNDI services.
However this only works under certain conditions, some of them:all clusters node running in ALL mode, all nodes located in the same subnet.
You can disable this behavior setting the InitialContext property jnp.disableDiscovery=true.
I guess there may be better ways to do it
According to the code, you are not catching the object polled from the JNDI, this implies that every time you need to execute a service, a new lookup (wich is a time consuming operation) has to be done. The ServiceLocator pattern suggests caching the lookup result for improving performance.

Categories