java.RMI socket creation details? - java

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.

Related

ImageIO.read(stream) fails to read the stream no matter the given stream

I have a method called createBufferedImageFromURI that takes a string that could be either a file system path or an URL, and creates a BufferedImage from the resource corresponding to that string.
The method code is the following:
private static BufferedImage createBufferedImageFromURI(String filePathOrUrl)
throws IOException
{
IHttpContext httpContext = com.genexus.ModelContext
.getModelContext().getHttpContext();
InputStream is = null;
try {
if (filePathOrUrl.toLowerCase().startsWith("http://") ||
filePathOrUrl.toLowerCase().startsWith("https://") ||
(httpContext.isHttpContextWeb() &&
filePathOrUrl.startsWith(httpContext.getContextPath())))
is = new URL(GXDbFile.pathToUrl(filePathOrUrl, httpContext))
.openStream();
else
is = getGXFile(filePathOrUrl).getStream();
return ImageIO.read(is);
} catch (IOException e) {
log.error("Failed to read image stream: " + filePathOrUrl);
throw e;
} finally {
is.close();
}
}
As you can see, the first part of the if - else block corresponds to the case where the string is an URL. It was working just fine until it suddenly didn't. The following started appearing in the webapp logs:
2023-02-14T09:25:30,286 [http-nio-8080-exec-13] ERROR com.genexus.GxImageUtil - getImageWidth https://static3.depositphotos.com/1000575/154/i/600/depositphotos_1549339-stock-photo-lithuania-landscape-panorama.jpg failed
java.lang.NullPointerException: Cannot invoke "java.awt.image.BufferedImage.getWidth()" because the return value of "com.genexus.GxImageUtil.createBufferedImageFromURI(String)" is null
at com.genexus.GxImageUtil.getImageWidth(GxImageUtil.java:79) ~[gxclassR-2.10-SNAPSHOT.jar:?]
at com.pruebasjavastable.webpanelimageapi_impl.e12042(webpanelimageapi_impl.java:771) ~[classes/:?]
at com.pruebasjavastable.webpanelimageapi_impl.strup040(webpanelimageapi_impl.java:736) ~[classes/:?]
at com.pruebasjavastable.webpanelimageapi_impl.start042(webpanelimageapi_impl.java:525) ~[classes/:?]
at com.pruebasjavastable.webpanelimageapi_impl.executeStartEvent(webpanelimageapi_impl.java:122) ~[classes/:?]
...
There is no other trace what could be the cause of this error. Neither on Tomcat's console or even in the browser console or network tab
I did some debugging to discard some obvious possible causes, but none of them where the case
GXDbFile.pathToUrl( filePathOrUrl, httpContext) builds the URL just fine. I even tried hard coding one and it still didn't work
Discarded some firewall or proxy issue by testing it on other PCs and networks. Even tried it on online playgrounds
Is there a problem with this implementation? As I said, it was working just fine until it suddenly didn't. Only change I can think of is that I changed my JDK from 17.0.4 to 17.0.6 but I read the release notes and nothing seems to affect my case.

Counting the number of instanced classes fails in debug mode

Working on a imgui port in kotlin, I have a metrics menu where I display the number of allocations
This is the init code I wrote:
try {
var ac: AttachingConnector? = null
for (x in Bootstrap.virtualMachineManager().attachingConnectors()) {
if (x.javaClass.name.toLowerCase().indexOf("socket") != -1) {
ac = x
break
}
}
if (ac == null) {
throw Error("No socket attaching connector found")
}
val connectArgs = HashMap<String, Argument>(ac.defaultArguments())
connectArgs["hostname"]!!.setValue("127.0.0.1")
connectArgs["port"]!!.setValue(Integer.toString(3001))
connectArgs["timeout"]!!.setValue("3000")
vm = ac.attach(connectArgs)
} catch (error: Exception) {
System.err.println("Couldn't retrieve the number of allocations, $error")
}
And these are the arguments I pass in as 'VM options'
-Xdebug -Xrunjdwp:transport=dt_socket,address=3001,server=y,suspend=n
Whenever I run it normally, it works. But if I run it in debug mode, it doesnt, returning the following error:
java.net.ConnectException: Connection refused: connect
I couldn't find yet a solution for that, at the moment I simply display a -1 to indicate an error
Does anyone have a solution/explanation about?
Specs:
Kotlin 1.2-m1
Idea 2017.2.1
I guess the problem is that you try to use the same port for the debugger as the one used by the program. Try to use a different port for the debugger.

NullPointerException when making XMPP connection through Smack 4.2.0

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

How do you handle EmptyResultDataAccessException with Spring Integration?

I have a situation where before I process an input file I want to check if certain information is setup in the database. In this particular case it is a client's name and parameters used for processing. If this information is not setup, the file import shall fail.
In many StackOverflow pages, the users resolve handling EmptyResultDataAccessException exceptions generated by queryForObject returning no rows by catching them in the Java code.
The issue is that Spring Integration is catching the exception well before my code is catching it and in theory, I would not be able to tell this error from any number of EmptyResultDataAccessException exceptions which may be thrown with other queries in the code.
Example code segment showing try...catch with queryForObject:
MapSqlParameterSource mapParameters = new MapSqlParameterSource();
// Step 1 check if client exists at all
mapParameters.addValue("clientname", clientName);
try {
clientID = this.namedParameterJdbcTemplate.queryForObject(FIND_BY_NAME, mapParameters, Long.class);
} catch (EmptyResultDataAccessException e) {
SQLException sqle = (SQLException) e.getCause();
logger.debug("No client was found");
logger.debug(sqle.getMessage());
return null;
}
return clientID;
In the above code, no row was returned and I want to properly handle it (I have not coded that portion yet). Instead, the catch block is never triggered and instead, my generic error handler and associated error channel is triggered instead.
Segment from file BatchIntegrationConfig.java:
#Bean
#ServiceActivator(inputChannel="errorChannel")
public DefaultErrorHandlingServiceActivator errorLauncher(JobLauncher jobLauncher){
logger.debug("====> Default Error Handler <====");
return new DefaultErrorHandlingServiceActivator();
}
Segment from file DefaultErrorHandlingServiceActivator.java:
public class DefaultErrorHandlingServiceActivator {
#ServiceActivator
public void handleThrowable(Message<Throwable> errorMessage) throws Throwable {
// error handling code should go here
}
}
Tested Facts:
queryForObject expects a row to be returned and will thrown an
exception if otherwise, therefore you have to handle the exception
or use a different query which returns a row.
Spring Integration is monitoring exceptions and catching them before
my own code can hand them.
What I want to be able to do:
Catch the very specific condition and log it or let the end user know what they need to do to fix the problem.
Edit on 10/26/2016 per recommendation from #Artem:
Changed my existing input channel to Spring provided Handler Advice:
#Transformer(inputChannel = "memberInputChannel", outputChannel = "commonJobGateway", adviceChain="handleAdvice")
Added support Bean and method for the advice:
#Bean
ExpressionEvaluatingRequestHandlerAdvice handleAdvice() {
ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
advice.setOnFailureExpression("payload");
advice.setFailureChannel(customErrorChannel());
advice.setReturnFailureExpressionResult(true);
advice.setTrapException(true);
return advice;
}
private QueueChannel customErrorChannel() {
return new DirectChannel();
}
I initially had some issues with wiring up this feature, but in the end, I realized that it is creating yet another channel which will need to be monitored for errors and handled appropriately. For simplicity, I have chosen to not use another channel at this time.
Although potentially not the best solution, I switched to checking for row counts instead of returning actual data. In this situation, the data exception is avoided.
The main code above moved to:
MapSqlParameterSource mapParameters = new MapSqlParameterSource();
mapParameters.addValue("clientname", clientName);
// Step 1 check if client exists at all; if exists, continue
// Step 2 check if client enrollment rules are available
if (this.namedParameterJdbcTemplate.queryForObject(COUNT_BY_NAME, mapParameters, Integer.class) == 1) {
if (this.namedParameterJdbcTemplate.queryForObject(CHECK_RULES_BY_NAME, mapParameters, Integer.class) != 1) return null;
} else return null;
return findClientByName(clientName);
I then check the data upon return to the calling method in Spring Batch:
if (clientID != null) {
logger.info("Found client ID ====> " + clientID);
}
else {
throw new ClientSetupJobExecutionException("Client " +
fileNameParts[1] + " does not exist or is improperly setup in the database.");
}
Although not needed, I created a custom Java Exception which could be useful at a later point in time.
Spring Integration Service Activator can be supplied with the ExpressionEvaluatingRequestHandlerAdvice, which works like a try...catch and let you to perform some logic onFailureExpression: http://docs.spring.io/spring-integration/reference/html/messaging-endpoints-chapter.html#expression-advice
Your problem might be that you catch (EmptyResultDataAccessException e), but it is a cause, not root on the this.namedParameterJdbcTemplate.queryForObject() invocation.

Java - Create domain in Amazon SimpleDB

I'm working with Amazon SimpleDB and attempting the creation of a DB using the following tutorial . Basically it throws an error i.e. Error occured: java.lang.String cannot be cast to org.apache.http.HttpHost. The full stacktrace is as below:
Error occured: java.lang.String cannot be cast to org.apache.http.HttpHost
java.lang.ClassCastException: java.lang.String cannot be cast to org.apache.http.HttpHost
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:416)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
at com.xerox.amazonws.common.AWSQueryConnection.makeRequest(AWSQueryConnection.java:474)
at com.xerox.amazonws.sdb.SimpleDB.makeRequestInt(SimpleDB.java:231)
at com.xerox.amazonws.sdb.SimpleDB.createDomain(SimpleDB.java:155)
at com.amazonsimpledb.SDBexample1.main(SDBexample1.java:19)
My code is as below (note i have substituted the AWS access id and secret key with the actual values):
public static void main(String[] args) {
String awsAccessId = "My aws access id";
String awsSecretKey = "my aws secret key";
SimpleDB sdb = new SimpleDB(awsAccessId, awsSecretKey, true);
try {
Domain domain = sdb.createDomain("cars");
System.out.println(domain);
} catch (com.xerox.amazonws.sdb.SDBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Any ideas as to why the above mentioned error is occurs.
I appreciate any assistance.
It seems you are using the Typica client library, which is pretty much unmaintained since mid 2011, see e.g. the rare commmits and the steady growing unresolved issues, where the latest one appears to be exactly yours in fact, see ClassCastException using Apache HttpClient 4.2:
According to the reporter, things appear to be functional once we downgrade back to Apache HttpClient 4.1, so that might be a temporary workaround eventually.
Either way I highly recommend to switch to the official AWS SDK for Java (or one of the other language SDKs), which isn't only supported and maintained on a regular fashion, but also closely tracks all AWS API changes (admittedly this isn't that critical for Amazon SimpleDB, which is basically frozen technology wise, but you'll have a much easier time using the plethora of AWS Products & Services later on).
In addition you could benefit from the AWS Toolkit for Eclipse in case you are using that IDE.
The SDK includes a couple of samples (also available via the Eclipse Toolkit wizard), amongst those one for SimpleDB - here's a condensed code excerpt regarding your example:
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(
awsAccessId, awsSecretKey);
AmazonSimpleDB sdb = new AmazonSimpleDBClient(basicAWSCredentials);
Region usWest2 = Region.getRegion(Regions.US_WEST_2);
sdb.setRegion(usWest2);
try {
// Create a domain
String myDomain = "MyStore";
System.out.println("Creating domain called " + myDomain + ".\n");
sdb.createDomain(new CreateDomainRequest(myDomain));
// ...
// Delete a domain
System.out.println("Deleting " + myDomain + " domain.\n");
sdb.deleteDomain(new DeleteDomainRequest(myDomain));
} catch (AmazonServiceException ase) {
// ...
} catch (AmazonClientException ace) {
// ...
}
Please try to create instance of SimpleDB with server and port and let me know if it works.
public SimpleDB objSimpleDB = null;
private String awsAccessKeyId = "access key";
private String awsSecretAccessKey = "secret key";
private boolean isSecure= true;
private String server = "sdb.amazonaws.com";
private int port=443;
try{
SimpleDB objSimpleDB = new SimpleDB(awsAccessKeyId, awsSecretAccessKey, isSecure, server, port);
Domain domain = objSimpleDB .createDomain("cars");
} catch (com.xerox.amazonws.sdb.SDBException e) {
//handle error
}

Categories

Resources