I intend to use Smack to send messages through Firebase CCS. I modified a simple CCS client for my Web App but when I try to make connection, it results in exception.
I am using Smack 4.2.0
Here is the process of connection.
1) The connection method which is in my client:
public void connect() throws XMPPException{
try{
config = XMPPTCPConnectionConfiguration.builder()
.setPort(Config.FCM_PORT)
.setHost("fcm-xmpp.googleapis.com")
.setXmppDomain("googleapis.com")
.setSecurityMode(/*Default; Explicit setting for emphasis*/SecurityMode.ifpossible)
.setSendPresence(true)
.setUsernameAndPassword(fcmServerUsername, mApiKey)
.setSocketFactory(SSLSocketFactory.getDefault())
.setDebuggerEnabled(mDebuggable)/* Launch a window with info about packets sent and received */
.build();
}
catch(XmppStringprepException e){
e.printStackTrace();
}
connection = new XMPPTCPConnection(config);
// Configuring Automatic reconnection
ReconnectionManager manager = ReconnectionManager.getInstanceFor(connection);
manager.setReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
manager.enableAutomaticReconnection();
// Connect now then login
try{
connection.connect();
connection.login();
}
// TODO: Handle the exceptions if possible appropriately
catch(SmackException sme){
logger.severe(sme.getMessage());
sme.printStackTrace();
}
catch(IOException ioe){
logger.severe(ioe.getMessage());
ioe.printStackTrace();
}
catch(InterruptedException ie){
logger.severe("Connection got interrupted!!");
ie.printStackTrace();
}
}
2) I traced the exception and I got it here: (Smack's source)
At the line - HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());
// AbstractXMPPConnection.java
protected List<HostAddress> populateHostAddresses() {
List<HostAddress> failedAddresses = new LinkedList<>();
if (config.hostAddress != null) {
hostAddresses = new ArrayList<>(1);
HostAddress hostAddress = new HostAddress(config.port, config.hostAddress);
hostAddresses.add(hostAddress);
}
else if (config.host != null) {
hostAddresses = new ArrayList<HostAddress>(1);
HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());
if (hostAddress != null) {
hostAddresses.add(hostAddress);
}
} else {
// N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName
hostAddresses = DNSUtil.resolveXMPPServiceDomain(config.getXMPPServiceDomain().toString(), failedAddresses, config.getDnssecMode());
}
// Either the populated host addresses are not empty *or* there must be at least one failed address.
assert(!hostAddresses.isEmpty() || !failedAddresses.isEmpty());
return failedAddresses;
}
The exception is NullPointerException and I found that getDNSResolver() returns null. Of all the sources I have referenced, there wasn't anything related to DNS resolver as it is supposed to be internally handled by Smack. So my question is, have I missed out some crucial configuration or step in making the connection?
EDIT: I asked here because Smack is vast lib and there might some config someone knows that I might have missed. I am unable to set DNSResolver directly
EDIT : ANSWER UPDATE
This is NOT a bug in Smack's source as their Upgrade Guide for 4.2.0 explicitly mentions:
**
API Changes
**
Warning: This list may not be complete
Introduced ConnectionConfiguration.setHostAddress(InetAddress)
In previous versions of Smack,
ConnectionConfiguration.setHost(String) could be used to set the
XMPP service's host IP address. This is no longer possible due to the
added DNSSEC support. You have to use the new connection configuration
ConnectionConfiguration.setHostAddress(InetAddress) instead.
This seems to be a bug because I solved it by providing the Host Address (which was supposed to be inferred from {Host, Domain}). So, how did I know to provide the host address?
The trick lies here: (Smack' source)
// AbstractXMPPConnection.java
if (config.hostAddress != null) {
hostAddresses = new ArrayList<>(1);
HostAddress hostAddress = new HostAddress(config.port, config.hostAddress);
hostAddresses.add(hostAddress);
}
else if (config.host != null) {
hostAddresses = new ArrayList<HostAddress>(1);
HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());
if (hostAddress != null) {
hostAddresses.add(hostAddress);
}
} else {
// N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName
hostAddresses = DNSUtil.resolveXMPPServiceDomain(config.getXMPPServiceDomain().toString(), failedAddresses, config.getDnssecMode());
}
You can see the if, else-if blocks here and since the exception arises in the else if (config.host != null) block, I provided hostAddress so that it never enters that block and it worked.
I know this is sort of a hack around the actual problem but this seems to be a bug in Smack 4.2.0 unless someone disproves me otherwise.
Bonus info: If after rectifying this problem, you get another exception in Base 64 encoding during login, refer to this - XMPP client using Smack 4.1 giving NullPointerException during login
Not sure in 4.2.0 but in 4.2.2 (and newer), you will need smack-resolver-dnsjava-4.2.2.jar to be in your classpath, smack calls DNSUtil which is included in the package, if the class doesn't exist it returns NullPointerException.
Hope this help!
David
Related
I'm using TransportClient to create elasticsearch client instance with below code.
public static Client getInstance() {
String ipAddress = MessageTranslator.getMessage("es.cluster.ip");
int transportClientPort = Integer.parseInt(MessageTranslator
.getMessage("es.transportclient.port"));
logger.debug("got the client ip as :" + ipAddress + " and port :"
+ transportClientPort);
if (instance == null) {
logger.debug("the client instance is null, creating a new instance");
ImmutableSettings.Builder settings = ImmutableSettings
.settingsBuilder();
settings.put("node.client", true);
settings.put("node.data", false);
settings.put("node.name", "node-client");
settings.put("cluster.name", "elasticsearch");
settings.build();
instance = new TransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(
ipAddress, transportClientPort));
logger.debug("returning the new created client instance...");
return instance;
}
logger.debug("returning the existing transport client object connection.");
return instance;
}
The issue is some times the code is working and indexing data, but some times I'm getting the below issue.
14-08-2014 12:49:07,846 DEBUG
[elasticsearch[node-client][transport_client_worker][T#8]{New I/O
worker #8}] org.elasticsearch.common.logging.log4j.Log4jESLogger 104 -
[node-client] disconnected from [[Nuke - Frank
Simpson][P_OU-PZbTXyimWCOvkC7ow][aricloudvmserver3.aricent.com][inet[/10.203.238.139:9300]]],
channel closed event 14-08-2014 12:49:11,134 DEBUG
[elasticsearch[node-client][generic][T#1]]
org.elasticsearch.common.logging.log4j.Log4jESLogger 109 -
[node-client] failed to connect to node
[[#transport#-1][BGHWV2099][inet[/10.203.238.139:9300]]], removed from
nodes list org.elasticsearch.transport.ConnectTransportException:
[][inet[/10.203.238.139:9300]] connect_timeout[30s] at
org.elasticsearch.transport.netty.NettyTransport.connectToChannelsLight(NettyTransport.java:683)
at
org.elasticsearch.transport.netty.NettyTransport.connectToNode(NettyTransport.java:643)
at
org.elasticsearch.transport.netty.NettyTransport.connectToNodeLight(NettyTransport.java:610)
Please help me to find the issue.
Thanks
Your code looks correct to me. If this is an intermittent issue, it can be attributed to:
Lost connectivity
Also as suggested in the previous post, remove the node related settings and try setting below mentioned properties
settingsBuilder.put("cluster.name", searchClusterName);
settingsBuilder.put("client.transport.sniff", true);
settingsBuilder.put("http.enabled", "false");
Try this out and share your findings
With Tomcat setup behind Apache, how can an id (IP address ideally) of the server be easily determined?
The specific situation is that multiple servers are setup behind a load balancer, thus the incoming request host name is non-unique and insufficient to identify a particular server for logging purposes. Using HttpServletRequest.getLocalAddr() is unfortunately returning the same hostname instead of the IP address as would be expected (I am assuming this is related to this very old issue here: https://issues.apache.org/bugzilla/show_bug.cgi?id=46082).
Is there a way to make getLocalAddr() perform as documented, or are other methods required to query the IP address of the server?
On our project, we use JMX to get all the config information.
It takes a few steps, because it is like navigating down the server.xml file
This link has some info: http://oss.wxnet.org/mbeans.html
It is probably overkill if all you want is the IP, but I thought I'd throw it out there.
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> theConnectors = mbeanServer.queryNames(
new ObjectName("Catalina:type=Connector,*"),
null);
if (theConnectors != null)
{
for (ObjectName nextConnectorName : theConnectors)
{
InetAddress theInetAddress = (InetAddress) mbeanServer.getAttribute(
nextConnectorName,
"address");
if (theInetAddress != null)
{
ipAddress = theInetAddress.getHostAddress();
}
if (!StringUtil.isEmpty(ipAddress))
{
// found the IP address
break;
}
}
}
For my situation, the solution was to get the IP address of the server directly instead of attempting to get the local address via HttpServleRequest.
I cached the IP for use in my filter via:
private static final String serverIp;
static {
String addressString = null;
try
{
InetAddress address = InetAddress.getLocalHost();
addressString = address.getHostAddress();
} catch (Exception e)
{
logger.error("Exception while attempting to determine local ip address",e);
}
if (addressString != null) serverIp = addressString;
else serverIp = "unknown";
}
I had a similar issue recently (a few years after the original question) and found this question and answers. The issue in my case was that the ServletRequest#getLocalAddr() implementation was returning the remote address instead of the local address. The issue was caused by a regression in Tomcat v9.0.22. It was fixed in v9.0.23. See the question and answer here:
https://stackoverflow.com/a/57725039/9602527
My aim is to put n number of messages in a for loop to a WebSphere MQ queue using WebSphere MQ java programming.
My java program will run as a standalone program.
If any exception in between , I need to rollback all the messages.
If no exception then I should commit all the messages .
The outside world should not see my messages in the queue until I complete fully.
How do I achieve this?
Updated with sample code as per reply from T.Rob:
Please check if sample code is fine ?
Does setting MQGMO_SYNCPOINT is only related to my program's invocation ?
(because similar programs running parallely will also be putting messages on the same queue and those messages should not gett affected by my program's SYNCPOINT.)
public void sendMsg() {
MQQueue queue = null;
MQQueueManager queueManager = null;
MQMessage mqMessage = null;
MQPutMessageOptions pmo = null;
System.out.println("Entering..");
try {
MQEnvironment.hostname = "x.x.x.x";
MQEnvironment.channel = "xxx.SVRCONN";
MQEnvironment.port = 9999;
queueManager = new MQQueueManager("XXXQMANAGER");
int openOptions = MQConstants.MQOO_OUTPUT;
queue = queueManager.accessQueue("XXX_QUEUENAME", openOptions, null, null, null);
pmo = new MQPutMessageOptions();
pmo.options = CMQC.MQGMO_SYNCPOINT;
String input = "testing";
System.out.println("sending messages....");
for (int i = 0; i < 10; i++) {
input = input + ": " + i;
mqMessage = new MQMessage();
mqMessage.writeString(input);
System.out.println("Putting message: " + i);
queue.put(mqMessage, pmo);
}
queueManager.commit();
System.out.println("Exiting..");
} catch (Exception e) {
e.printStackTrace();
try {
System.out.println("rolling back messages");
if (queueManager != null)
queueManager.backout();
} catch (MQException e1) {
e1.printStackTrace();
}
} finally {
try {
if (queue != null)
queue.close();
if (queueManager != null)
queueManager.close();
} catch (MQException e) {
e.printStackTrace();
}
}
}
WMQ supports both local and global (XA) units of work. The local units of work are available simply by specifying the option. Global XA transactions require a transaction manager, as mentioned by keithkreissl in another answer.
For what you described, a POJO doing messaging under syncpoint, specify MQC.MQGMO_SYNCPOINT in your MQGetMessageOptions. When you are ready to commit, issue the MQQManager.commit() or MQQManager.backout() call.
Note that the response and doc provided by ggrandes refers to the JMS and not Java classes. The Java classes use Java equivalents of the WMQ procedural API, can support many threads (doc) and even provide connection pooling (doc). Please refer to the Java documentation rather than the JMS documentation for the correct behavior. Also, I've linked to the WMQ V7.5 documentation which goes with the latest WMQ Java V7.5 client. The later clients have a lot more local functionality (tracing, flexible install path, MQClient.ini, etc.) and work with back-level QMgrs. It is highly recommended to be using the latest client and the download is free.
you only need to create a session with transaction enabled.
Session session;
// ...
boolean transacted = true;
session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
try {
// ...do things...
session.commit();
} catch (Exception e) {
session.rollback();
}
// ...
WARN-NOTE: Sessions are not thread-safe ;-)
Doc Websphere MQ/JMS
If you have access to a transaction manager and more importantly an XATransaction wired up to your MQ access, you can start a transaction at the beginning of your message processing put all the messages on the queue then commit the transaction. Using the XATransactions it will not put any messages until the transaction commits. If you don't have access to that, you can do a little more plumbing by placing your messages in a local data object, wrap your code in a try/catch if no exceptions iterate through the local data object sending the messages. The issue with the later approach is that it will commit all your other processing but if a problem occurs in the sending of messages your other processing will not be rolled back.
I've checked the other answers and they didn't help me with this error. Maybe I'm doing something else wrong.
Here's my code:
void uploadPic() throws FileNotFoundException
{
FileInputStream fis = new FileInputStream(path);
FTPClient con = new FTPClient();
int bytesAvailable;
try
{
con.connect("ftp://ftp.drivehq.com/");
Toast.makeText(this, "Connected to FTP", Toast.LENGTH_SHORT).show();
if (con.login("x", "x"))
{
Toast.makeText(this, "Logged in", Toast.LENGTH_SHORT).show();
con.enterLocalPassiveMode(); // Active mode doesn't really work on Android
bytesAvailable = fis.available();
byte[] barray = new byte[bytesAvailable];
fis.read(barray);
ByteArrayInputStream in = new ByteArrayInputStream(barray);
boolean result = con.storeFile("/CameraUpload.jpg", in);
in.close();
if (result) Log.v("Upload Result", "Succeeded");
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
I've added INTERNET permission to my project.
The logcat shows these errors:
android.os.NetworkOnMainThreadException
W/System.err(17531): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099)
W/System.err(17531): at java.net.InetAddress.lookupHostByName(InetAddress.java:391
I'm connected to the internet via Wifi.
That exception seems to be thrown when you try to perform network operations (such as FTP) from your main thread. This is not allowed for performance reasons (so that the application doesn't appear to lock up to the user, when performing an action which may take a while). Assuming you are using Honeycomb or higher, you would need to move the code that makes the connection into its own child thread.
http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
http://developer.android.com/guide/practices/design/responsiveness.html
Most likely, this error means that your device cannot resolve ftp.drivehq.com to its IP address. I can't say for sure because you only pasted part of the error log. Make sure you have network connection and that your DNS is working correctly. See if you can connect to this same site via android browser, for example.
i've looked at doc, tested, debugged ... but remain stumped. time for stackOverflow! i'll set the stage, then describe my error.
Background
i have an RMI client/sever setup that works fine when client, server and rmiregistry
all live together on localhost. so then i fire up rmiregistry on serverHost, with rmi.server.logCalls trace turned on (called RegistryTrace below). the important parts of the server code:
String hostname = "//serverHost.local/project"
String codeBase = "file:/home/rik/Code/eclipse/project/bin/"
System.setProperty("java.rmi.server.hostname", hostname);
System.setProperty("java.rmi.server.codebase", codeBase);
Driver server = new Driver();
Naming.rebind(hostname, server);
when i start the server, i see the rebind() call succeeds (by looking at RegistryTrace). also, looking at the list generated by Naming.list() shows it contains "//serverHost.local:1099/project"
starting my client, it successfully completes Naming.lookup():
server = (ServerInterface)Naming.lookup(serverHost);
looking at RegistryTrace, i am able to confirm that this lookup() query gets to the server end.
Error on first RMI
but now: my next statement tries to call one of server's methods
boolean status = server.initConnection(username);
generates an IllegalArgumentException:
java.lang.IllegalArgumentException: protocol = socket host = null
at sun.net.spi.DefaultProxySelector.select(DefaultProxySelector.java:151)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:424)
at java.net.Socket.connect(Socket.java:529)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.<init>(Socket.java:375)
at java.net.Socket.<init>(Socket.java:189)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:110)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
at $Proxy0.initConnection(Unknown Source)
at project.client.View2.main(View2.java:651)
i've traced this down into Java source to a call to java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod()
private Object invokeRemoteMethod(Object proxy,
Method method,
Object[] args)
throws Exception
{
try {
if (!(proxy instanceof Remote)) {
throw new IllegalArgumentException(
"proxy not Remote instance");
}
// EXCEPTION OCCURS WITHIN CALL TO ref.invoke() BELOW
//
return ref.invoke((Remote) proxy, method, args,
getMethodHash(method));
} catch (Exception e) {
if (!(e instanceof RuntimeException)) {
Class<?> cl = proxy.getClass();
try {
method = cl.getMethod(method.getName(),
method.getParameterTypes());
} catch (NoSuchMethodException nsme) {
throw (IllegalArgumentException)
new IllegalArgumentException().initCause(nsme);
}
Class<?> thrownType = e.getClass();
for (Class<?> declaredType : method.getExceptionTypes()) {
if (declaredType.isAssignableFrom(thrownType)) {
throw e;
}
}
e = new UnexpectedException("unexpected exception", e);
}
throw e;
}
}
then i lose it in the source trace. (anyone know the story about source availability for things like sun.rmi.server.UnicastRef ?) the rest of the trace makes it seem like RMI can't create a socket?
i'm sure many parts of this code could be cleaner; any suggestions appreciated. i also need to convert this into jar file distributions, so if specifying them now for java.rmi.server.codebase would be easier...?
thanks for any suggestions, rik
It is constructing a SocksSocketImpl so you must be specifying an invalid SOCKS proxy host or port via socks.proxyHost/socks.proxyPort at the client, or perhaps you have java.rmi.server.hostname set to a strange value at the server.