When I run the client it's supposed to send an email to my server and then I want my email server to print out the email details (to, from, port, message) to console. For some reason after running the client, nothing apparent happens on the server.
server
package example;
import org.subethamail.smtp.server.SMTPServer;
public class EmailServer {
public static void main(String[] args) {
MyMessageHandlerFactory myFactory = new MyMessageHandlerFactory();
SMTPServer smtpServer = new SMTPServer(myFactory);
smtpServer.setPort(25000);
smtpServer.start();
}
}
server output
run: [main] INFO org.subethamail.smtp.server.SMTPServer - SMTP server
*:25000 starting [org.subethamail.smtp.server.ServerThread *:25000] INFO org.subethamail.smtp.server.ServerThread - SMTP server *:25000
started
client
package example;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.subethamail.smtp.client.*;
public class EmailClient {
public static void main(String[] args) {
try {
SMTPClient sc = new SMTPClient();
sc.close();
sc.connect("localhost", 25000);
sc.sendReceive("test");
} catch (IOException ex) {
Logger.getLogger(EmailClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
client output
run: BUILD SUCCESSFUL (total time: 0 seconds)
Version is 3.1.7 from https://code.google.com/p/subethasmtp/downloads/list
The server requires MyMessageHandlerFactory which I copied from: https://code.google.com/p/subethasmtp/wiki/SimpleExample
OK, let's check the source code (always a good idea) and see what happens.
You send "test" via
SMTPClient sc;
sc.sendReceive("test"); // which is actually sent to your SMTPServer as "test\r\n"
Now, considering that this is a new SMTP conversation (see RFC5321 for everything you always wanted to know but were afraid to ask about such things) and "test" isn't a valid command VERB at this point in the conversation, you would expect to see an error returned by sendReceive().
But since you're ignoring the SMTPClient.Response#75 returned from what should have been
Response resp=SMTPClient.sendReceive()
you're missing out on both
resp.code (which I am sure is 500 - Permanent Negative Completion reply / Syntax - see the RFC above) and
resp.message describing the reason your command could not be fulfulled
both of which are returned from CommandHandler#93.
Related
Forgive me for the newb question, but I am confused and obviously not understanding the fundamentals or explanations of how to use a Websocket server hosted over HTTPS. Everything I find online leads me to have more questions than answers.
I have a Websocket server hosted on my HTTPS website using Java code.
This is my WebsocketServer.java file:
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class WebsocketServer extends WebSocketServer {
private static final Logger logger = LogManager.getLogger(WebsocketServer.class);
private static int TCP_PORT = 6868;
private static Set<WebSocket> conns;
public WebsocketServer() {
super(new InetSocketAddress(TCP_PORT));
conns = new HashSet<>();
}
#Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
conns.add(conn);
logger.info("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
logger.info("Size of connection list: " + conns.size());
}
#Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
conns.remove(conn);
logger.info("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onMessage(WebSocket conn, String message) {
logger.info("Message from client: {}", message);
// for (WebSocket sock : conns) {
// sock.send("SENDING BACK" + message);
// }
}
#Override
public void onError(WebSocket conn, Exception ex) {
// ex.printStackTrace();
try {
if (conn != null) {
conns.remove(conn);
// do some thing if required
}
logger.info("ERROR from {}", conn.getRemoteSocketAddress().getAddress().getHostAddress());
} catch (Exception e) {
logger.info("onError: WebSocketServer may already be running");
}
}
public Set<WebSocket> getConns() {
return conns;
}
}
Then I started the WebsocketServer like this:
WebsocketServer websocketServer;
// Start socket server
websocketServer = new WebsocketServer();
websocketServer.start();
And on the client side, I connect to it like this:
// APP_WEB_SOCKET is the url to my site: api.my_custom_domain.com
var connection = new WebSocket("wss://" + APP_WEB_SOCKET + ":6868");
QUESTIONS:
I keep reading that I need a certificate if I want to use wss over HTTPS, but cannot find any documents that explain what this means in a way that I can understand.
My app is hosted in AWS Elastic Beanstalk environment. Do I need to somehow add a certificate to the setup of the WebsocketServer in my Java code?
Example:
WebsocketServer websocketServer;
// Start socket server
websocketServer = new WebsocketServer();
// example guessing
websocketServer.cert = "SOMETHING";??
websocketServer.start();
Does the client code need to be changed at all?
Who needs the certificate?
If someone could please explain what I am missing or point me in the correct direction, I would really appreciate it.
Keep it easy.
Certs inside your application are complex - they are hard to manage and you will get problems to run your application in a modern cloud environment (start new environments, renew certs, scale your application, ...).
Simple conclusion: Dont implement any certs.
How-to get encrypted connections?
As Mike already pointed out in the comments: WebSockets are just upgraded HTTP(S) connections. A normal webserver (nginx, apache) takes care about the certs. It can be done in kubernetes (as ingress-controller) or with a "bare-metal" webserver.
Both of them should act as a reverse-proxy. This means: Your java-application doesn't know anything about certs. It has just unencrypted connections - like in your code on port 6868.
But the client will not use this port. 6868 is only internally reachable.
The client will call your reverse-proxy at the normal HTTPS port (=443). The reverse-proxy will forward the connection to your java-application.
Here some links for further information:
nginx reverse-proxy
nginx reverse-proxy for websocket
tutorial for java behind reverse-proxy
LetsEncrypt for automatic and free certs
I am copying the simplest web service example from CXF; it steps through writing an interface, then an implementation file, to say hello to a name provided by the webservice consumer. I changed a package name and the method name because I wanted to see where things showed up; if you name everything HelloWorld you can't see what is method, package, class, etc.
Those instructions include a program to publish the web service. After I do that, putting the URL
http://localhost:9000/helloWorld?wsdl
in a browser displays a wsdl file that contains enough stuff the way I spelled it to convince me that it was generated from my code. I assume, based on this, that both the WSDL generation and the publication worked.
This is the service interface:
package hw;
import javax.jws.WebParam;
import javax.jws.WebService;
#WebService
public interface HelloWorld
{
String sayHi(#WebParam(name="firstName") String firstName);
}
This is the service implementation:
package hwimpl;
import javax.jws.WebService;
#WebService(endpointInterface = "hw.HelloWorld", serviceName = "HelloWorld")
public class HelloWorldImpl
{
static public void say(String msg) { System.out.println(msg); }
public String sayHi(String firstName)
{ say ("sayHi called with " + firstName);
return "Hello " + firstName + " from the World.";
}
}
And this is the publishing program:
package hwimpl;
import javax.xml.ws.Endpoint;
public class PublishHelloWorldService
{
protected PublishHelloWorldService() throws Exception
{
// START SNIPPET: publish
System.out.println("Starting Server");
HelloWorldImpl implementor = new HelloWorldImpl();
String address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, implementor);
// END SNIPPET: publish
}
public static void main(String args[]) throws Exception
{
new PublishHelloWorldService();
System.out.println("Server ready...");
Thread.sleep(5 * 60 * 1000);
System.out.println("Server exiting");
System.exit(0);
}
}
Now I compile and run this program:
package client;
import hw.HelloWorld;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
public final class HelloWorldClient
{
private static final QName SERVICE_NAME = new QName("http://server.hw.demo/", "HelloWorld");
private static final QName PORT_NAME = new QName("http://server.hw.demo/", "HelloWorldPort");
private HelloWorldClient()
{
}
public static void main(String args[]) throws Exception
{
Service service = Service.create(SERVICE_NAME);
String endpointAddress = "http://localhost:9000/helloWorld";
// If web service deployed on Tomcat deployment, endpoint should be changed
// to:
// String
// endpointAddress =
// "http://localhost:8080/java_first_jaxws/services/hello_world";
// Add a port to the Service
service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
HelloWorld hw = service.getPort(HelloWorld.class);
System.out.println(hw.sayHi("Albert"));
}
}
and I get this error:
Exception in thread "main" javax.xml.ws.WebServiceException: Could not send Message.
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)
at com.sun.proxy.$Proxy20.sayHi(Unknown Source)
at client.HelloWorldClient.main(HelloWorldClient.java:37)
Caused by: java.net.MalformedURLException: Invalid address. Endpoint address cannot be null.
at org.apache.cxf.transport.http.HTTPConduit.getURL(HTTPConduit.java:872)
at org.apache.cxf.transport.http.HTTPConduit.getURL(HTTPConduit.java:854)
at org.apache.cxf.transport.http.HTTPConduit.setupURL(HTTPConduit.java:800)
at org.apache.cxf.transport.http.HTTPConduit.prepare(HTTPConduit.java:548)
at org.apache.cxf.interceptor.MessageSenderInterceptor.handleMessage(MessageSenderInterceptor.java:46)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:516)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:313)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:265)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
... 2 more
I am running the programs -- both publish and client -- from eclipse. The eclipse is set up with proxies for http and https in Window / Preferences; I removed the one for http before running the client, but it did not change the message.
It is in fact a tomcat server; I tried the alternate URL in the publish program with no change.
I don't run tomcat from within eclipse in this case; I run it by itself on my machine and then run the publish program (from eclipse), verify the url that displays the wsdl works correctly, and then run the client program (from eclipse) and get my error.
Can someone tell me what I'm doing wrong? I've seen other posts on this exact error message, but none of the answers were definitive and I appear to have tried them all.
Not sure this is your problem.
I've sometimes had problems with eclipse not being able to run tomcat applications on a running tomcat as you describe in your example.
What I sometimes have to do when working with tomcat and eclipse is either
have a running tomcat (windows service) and then export my eclipse application to that tomcat
stop the running tomcat on that port from windows services and start the tomcat from inside eclipse when running the program.
For some reason eclipse seems to have problems with an already running tomcat.
I have a JNLP downloader application deployed on remote user machines that downloads files.
I need to get some error feedback mailed to me. Not so much exceptions, just things getting stuck, or stalled or in infinite loops.
Currently I have a basic handler:
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class javaerrorlog {
private static Logger l = Logger.getLogger("");
public static void main(String args[]) throws Exception{
FileHandler handler = new FileHandler("log.txt");
l.addHandler(handler);
l.setLevel(Level.ALL);
l.info("Error logs");
try {
} catch (Error ex) {
l.log(Level.INFO, "", ex);
}
l.fine("");
}
}
Also, should I prompt for the client's permission to send error reporting data?
If you just need notifications you could use something like SMTPHandler. If you need it more fancy you could use JMS with an MDB.
I have some code to connect to the internet, it works fine in the simulator
but when I try it on a real device, I always get a 400 http response code
(the response body says "Connection timed out")
I'm using JRE 5
and using Blackberry 9000 on OS version 5 for both the real device and the simulator.
It is activated according to Advanced Options > Enterprise Activation
Is there something else I need to change on the real device to make it work?
I slowly whittled down my code to get to the root of the issue
and I'm down to this code:
package mypackage;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import net.rim.device.api.io.transport.TransportInfo;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.container.MainScreen;
public class MyApp extends UiApplication {
public static void main(String[] args) {
MyApp theApp = new MyApp();
theApp.enterEventDispatcher();
}
public MyApp() {
pushScreen(new SimpleScreen());
}
}
class SimpleScreen extends MainScreen {
public SimpleScreen() {
this.setTitle("Hello");
ConnectionThread ct = new ConnectionThread();
ct.start();
}
}
class ConnectionThread extends Thread {
private static String url = "http://www.wikipedia.org/";
public void run() {
System.out.println(" -- ConnectionThread.run()");
System.out.println(" ---- MDS hasSufficientCoverage? " + TransportInfo.hasSufficientCoverage(TransportInfo.TRANSPORT_MDS));
try {
HttpConnection httpConn;
httpConn = (HttpConnection) Connector.open(url);
final int iResponseCode = httpConn.getResponseCode();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("Response code: " + Integer.toString(iResponseCode));
}
});
} catch (Exception e) {
System.err.println("Caught IOException: " + e.getMessage());
}
System.out.println(" -- /ConnectionThread.run()");
}
}
==============================================
// EDIT:
I'm pretty sure its a device config issue now, I just the Network Diagnostic Tool and it also returns a 400 HTTP Response with the message "connect timed out".
==============================================
//EDIT #2:
I just tried options->mobile network->diagnostics test
Here are the results:
ICMP Ping Echo: No
------
Blackberry Registration: Yes
Connected to Blackberry: Yes
Blackberry PIN-PIN: Yes
------
Server Name: <my enterprise server>
Email Address: <my email>
Connected to <my email>: Yes
Then I tried options->mobile network->tools->ping
and pinged google and wikipedia and both say A network error occurred
Are you sure that your BB device is connected to any BES server? I would suggest that you first try to access internet from BB browser.
I asked the BES Admin and he says its Docomo issue.. and he has taken it up with them.
Basically there's no code problem (as far as I can tell)
We found this issue while implementing a reconnect logic for a WS endpoint using JAX-WS stack deployed on Glassfishv2.1 server. We deploy the web service on a cluster environment. To simplify the deployment, we use 0.0.0.0 as the IP on which the endpoint needs to be published, so that it can be accessed from all available IPs pertaining to the nodes of the cluster. Following is the code snippet for initialization of the WS(Web Service):
import javax.xml.ws.Endpoint;
.
.
//Implementor is the corresponding implementation object for the WS
Endpoint receiver = Endpoint.create(new Implementor());
.
receiver.setExecutor(threadPoolExecutor);
receiver.publish ("http://0.0.0.0:9545/context");
We call receiver.stop() to stop publishing the endpoint in our cleanup code. That's where we receive a null pointer exception with the following stack trace:
java.lang.NullPointerException
at com.sun.xml.ws.transport.http.server.ServerMgr.removeContext(ServerMgr.java:123)
at com.sun.xml.ws.transport.http.server.HttpEndpoint.stop(HttpEndpoint.java:110)
at com.sun.xml.ws.transport.http.server.EndpointImpl.stop(EndpointImpl.java:167
While trying to find the cause of the NPE, we found that the ServerMgr class depends on the InetSocketAddress of the HttpServer that listen on the ip:port of the URL where the WS endpoint is published, to retrieve some state information from a map. Since the inet address "inet:/0.0.0.0" is interpreted as "inet:/0:0:0:0:0:0:0:0" it could not find the entry in the map and hence the NPE. Here is the source code of ServerMgr.
In order to prove that this is in fact the problem, we tried to replicate the logic of the ServerMgr code related to InetSocketAddress as the following program:
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
static final String URL_1 = "http://0.0.0.0:9545/context";
static final String URL_2 = "http://127.0.0.1:9548/context";
static final String URL_3 = "http://10.226.90.217:9549/context";
public void testUrl(String address){
try {
URL url = new URL(address);
Map<InetSocketAddress, Integer> map = new HashMap<InetSocketAddress, Integer>();
InetSocketAddress iaddr = new InetSocketAddress(url.getHost(), url.getPort());
map.put(iaddr, 1);
HttpServer server = HttpServer.create(iaddr, 5);
HttpContext context = server.createContext(url.toURI().getPath());
server.start();
System.out.println("original inet:"+iaddr+" and final inet:"+context.getServer().getAddress());
if(iaddr.equals(context.getServer().getAddress())){
System.out.println("equal");
Integer t = map.get(context.getServer().getAddress());
if( t == null){
System.out.println("You won");
}else{
System.out.println("You lose "+t);
}
}else{
System.out.println("not-equal");
}
server.stop(0);
map.clear();
} catch (URISyntaxException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args)
{
Main d = new Main();
d.testUrl(Main.URL_1);
d.testUrl(Main.URL_2);
d.testUrl(Main.URL_3);
}
}
Odd enough we obtain the following result in my WindowsXP box ( Java version 1.6.0_22)
equal--
original inet:/0.0.0.0:9545 and final inet:/0.0.0.0:9545
equal
You lose 1
equal--
original inet:/127.0.0.1:9548 and final inet:/127.0.0.1:9548
equal
You lose 1
equal--
original inet:/10.226.92.47:9549 and final inet:/10.226.92.47:9549
equal
You lose 1
and the following output on my dev box
(Linux tahoe 2.6.9-67.EL #1 Wed Nov 7 13:43:31 EST 2007 x86_64 x86_64 x86_64 GNU/Linux)
(Java version 1.6.0_17)
run:
original inet:/0.0.0.0:9545 and final inet:/0:0:0:0:0:0:0:0:9545
not-equal
original inet:/127.0.0.1:9548 and final inet:/127.0.0.1:9548
equal
You lose 1
original inet:/10.226.90.217:9549 and final inet:/10.226.90.217:9549
equal
You lose 1
Based on the background - I have two questions:
a. Why is the 0.0.0.0 is interpreted
as IPv6 address ? (In addition, is it a problem
with the OS or the JRE ? Is it a bug
or a feature ? etc)
b. Do we have a way to configure
JRE to interpret 0.0.0.0 as IPv4 address ?
(We want to keep using 0.0.0.0 as the endpoint
address as it simplifies deployment
of our Web Service)
You can replace the 0.0.0.0 with InetAddress.getLocalHost().getHostAddress();
It will automatically resolve correctly and there is no need of -Djava.net.preferIPv4Stack=true
Have you tried by forcing the IPv4 choice as a variable to the java executable?
-Djava.net.preferIPv4Stack=true
Take a look here and here..
It's also possible to force IPv4 from your code with System.setProperty("java.net.preferIPv4Stack" , "true");