I need to run my own logic after the jetty embedded server starts. I'm not starting it from the main class due to classloader issues. An ideal solution seemed to be running my server logic from a servlet initialization. But the init function and also the constructor is not called after the jetty server start. An instance of the servlet is being created during the first HTTP request. Is it possible to tell jetty to initialize my servlet instantly or do I really need to load all classes with my custom classloader and then start the jetty server?
This is the main class:
public class ServerLauncher {
public static void main(String[] args) {
JettyServerLauncher.launchHttp("target/server.war", "0.0.0.0", 8080);
// Starting my own logic here is causing classloader issues, because WebSocket classes are loaded by other classloader than my classes, that is the reason why I moved it into the servlet
}
}
This is my jetty embedded server launcher:
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.webapp.*;
import java.io.File;
public class JettyServerLauncher {
private static boolean isHttps;
private static File keyStoreFile;
private static String warPath;
private static String host;
private static int httpPort;
private static int httpsPort;
private static String keyStorePath;
private static String keyStorePass;
private static boolean needClientAuth;
public static void launchHttp(String warPath, String host, int httpPort) {
JettyServerLauncher.isHttps = false;
JettyServerLauncher.warPath = warPath;
JettyServerLauncher.host = host;
JettyServerLauncher.httpPort = httpPort;
launch();
}
public static void launchHttps(String warPath, String host, String keyStorePath, String keyStorePass, int httpPort, int httpsPort, boolean needClientAuth) {
JettyServerLauncher.isHttps = true;
JettyServerLauncher.warPath = warPath;
JettyServerLauncher.host = host;
JettyServerLauncher.httpPort = httpPort;
JettyServerLauncher.httpsPort = httpsPort;
JettyServerLauncher.keyStorePath = keyStorePath;
JettyServerLauncher.keyStorePass = keyStorePass;
JettyServerLauncher.needClientAuth = needClientAuth;
launch();
}
private static void launch() {
Server server = null;
try {
System.out.println("Initializing jetty server...");
if (isHttps) loadKeyStores(keyStorePath);
// Create jetty server
server = new Server(httpPort);
// Setup connectors
Connector httpConnector = createHttpConnector(server, host, httpPort, httpsPort);
if (isHttps) {
Connector httpsConnector = createHttpsConnector(server, host, httpsPort, keyStoreFile, keyStorePass, needClientAuth);
server.setConnectors(new Connector[]{httpConnector, httpsConnector});
} else {
server.setConnectors(new Connector[]{httpConnector});
}
// Add handlers for requests to collection of handlers
HandlerCollection handlers = new ContextHandlerCollection();
//handlers.addHandler(new SecuredRedirectHandler());
handlers.addHandler(createWebApp(warPath));
server.setHandler(handlers);
server.dump();
System.out.println("Starting jetty websocket and web server...");
server.start();
server.join();
} catch (Throwable t) {
t.printStackTrace();
System.err.println("Server initialization failed!");
System.out.println("Stopping the server...");
try {
server.stop();
} catch (Exception ignored) {}
}
}
private static WebAppContext createWebApp(String warPath) {
WebAppContext webApp = new WebAppContext();
webApp.setContextPath("/");
webApp.setWar(new File(warPath).getAbsolutePath());
webApp.setThrowUnavailableOnStartupException(true);
// Enable support for JSR-356 javax.websocket
webApp.setAttribute("org.eclipse.jetty.websocket.jsr356", Boolean.TRUE);
// Jetty will scan project for configuration files... This is very important for loading websocket endpoints by annotation automatically
webApp.setConfigurations(new Configuration[] {
new AnnotationConfiguration(),
new WebInfConfiguration(),
new WebXmlConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new JettyWebXmlConfiguration()
});
return webApp;
}
private static Connector createHttpConnector(Server server, String host, int httpPort, int httpsPort) {
HttpConfiguration httpConf = new HttpConfiguration();
httpConf.setSendServerVersion(false);
if (isHttps) httpConf.setSecurePort(httpsPort);
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConf));
connector.setPort(httpPort);
connector.setHost(host);
return connector;
}
private static Connector createHttpsConnector(Server server, String host, int httpsPort, File keyStoreFile, String keyStorePass, boolean needClientAuth) {
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keyStoreFile.getAbsolutePath());
sslContextFactory.setKeyStorePassword(keyStorePass);
sslContextFactory.setNeedClientAuth(needClientAuth);
// Setup HTTPS Configuration
HttpConfiguration httpsConf = new HttpConfiguration();
httpsConf.setSendServerVersion(false);
httpsConf.setSecureScheme("https");
httpsConf.setSecurePort(httpsPort);
httpsConf.setOutputBufferSize(32768);
httpsConf.setRequestHeaderSize(8192);
httpsConf.setResponseHeaderSize(8192);
httpsConf.addCustomizer(new SecureRequestCustomizer()); // adds ssl info to request object
// Establish the HTTPS ServerConnector
ServerConnector httpsConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(httpsConf));
httpsConnector.setPort(httpsPort);
httpsConnector.setHost(host);
return httpsConnector;
}
private static void loadKeyStores(String keyStorePath) {
keyStoreFile = new File(keyStorePath);
if (!keyStoreFile.exists()) {
throw new RuntimeException("Key store file does not exist on path '"+keyStoreFile.getAbsolutePath()+"'");
}
}
}
This is my servlet:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#WebServlet(displayName = "MyServlet", urlPatterns = { "/*" })
public class MyServlet extends HttpServlet {
#Override
public void init() {
// start new Thread with my server logic here (avoid classloader issues)
// but at least one HTTP request is needed to start it from this place
}
#Override
public void destroy() {}
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
// handle http requests
}
}
I found this on google, but I don't know how to use it in my case. https://www.eclipse.org/lists/jetty-users/msg02109.html
Thank you for your help.
If you just want the servlet to init on startup, then use the annotation ...
#WebServlet(
displayName = "MyServlet",
urlPatterns = { "/*" },
loadOnStartup = 1
)
Alternatively, you could register a javax.servlet.ServletContextListener that does the contextInitialized(ServletContextEvent sce) behavior you need.
Tip: if you define a custom the ServletContextListener for embedded use, you can just add it to the WebAppContext from outside of the WAR you are using.
Example:
webApp.getServletHandler()
.addListener(new ListenerHolder(MyContextListener.class));
Also, this block of code is wrong and shows you copy/pasted from an old code snippet (this technique is from circa Jetty 9.0.0 thru 9.2.16)
webApp.setConfigurations(new Configuration[] {
new AnnotationConfiguration(),
new WebInfConfiguration(),
new WebXmlConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration(),
new PlusConfiguration(),
new JettyWebXmlConfiguration()
});
In Jetty 9.4.x you never directly configure the webApp.setConfigurations() like that, use the Configuration.ClassList defined on the server instead ...
From: 9.4.44.v20210927 - embedded/LikeJettyXml.java
Configuration.ClassList classlist = Configuration.ClassList
.setServerDefault(server);
classlist.addAfter(
"org.eclipse.jetty.webapp.FragmentConfiguration",
"org.eclipse.jetty.plus.webapp.EnvConfiguration",
"org.eclipse.jetty.plus.webapp.PlusConfiguration");
classlist.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
Starting in Jetty 10.0.0, you never specify the Configuration classes, or their order, as the existence of the support JAR is enough, and internally in Jetty 10 the order is resolved properly.
But if you need to add Configurations (due to non-standard deployment concerns where the Java ServiceLoader doesn't work), then you still configure the additional Configurations on the server object (but without worrying about the correct order for those configurations)
From 10.0.7 - embedded/demos/LikeJettyXml.java
Configurations.setServerDefault(server).add(
new EnvConfiguration(),
new PlusConfiguration(),
new AnnotationConfiguration()
);
I have an EJB Client as follow:
public class EJBTestClient {
public static void main(String[] args) throws NamingException {
Properties jndiProps = new Properties();
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
jndiProps.put(Context.PROVIDER_URL,"http-remoting://localhost:8080"); // create a context passing these properties Context ctx = new InitialContext(jndiProps);
jndiProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext context = new InitialContext(jndiProps);
System.out.println("Context lookup finished");
MyFirstEJBRemote proxy = (MyFirstEJBRemote) context.lookup("MyFirstEJB/Remote");
System.out.println(proxy.getClass().toString());
System.out.println(proxy.getDescription());
proxy.doSomething();
}
}
but when I run the program it showed an Exception javax.naming.CommunicationException: Failed to connect to any server. Servers tried: [http-remoting://127.0.0.1:8080 (java.io.IOException: JBREM000202: Abrupt close on Remoting connection 0c05035f to /127.0.0.1:8080 of endpoint "config-based-naming-client-endpoint" <2ce1483d>)]
And my EJB Container named EJBTestApp which contains MyFirstEJB Stateless Session Bean and MyFirstEJBRemote Interface:
#Stateless
#Remote
public class MyFirstEJB implements MyFirstEJBRemote {
private Logger log = Logger.getLogger(MyFirstEJB.class);
/**
* Default constructor.
*/
public MyFirstEJB() {
// TODO Auto-generated constructor stub
}
#Override
public void doSomething() {
log.info("doSomething() has been call");
}
#Override
public String getDescription() {
return "getDescription() has returned some values";
}
}
And this EJB Container is deployed on Wildfly 10 under localhost:8080. Can anyone help me how to solve this problem
Try to set
jndiProps.put(jboss.naming.client.ejb.context, true);
Add the libraries from wildfly10directory/bin/client to the project
If doesn't working, try to set lookup to:
MyFirstEJBRemote proxy = (MyFirstEJBRemote) context.lookup("MyFirstEJB/BeanName!path_to_package_remote_bean");
I am new to Spring Boot but have been requested by my job to implement a small web service using spring boot.
The web service needs to accept SSL TCP connections (an external system will connect to my web service using a custom protocol - NOT HTTP). Also, I would like to handle these connections in a background task (or multiple background tasks).
After looking at the official documentation (http://docs.spring.io/spring-integration/reference/html/ip.html), I still don't understand (where do I place all that XML). When I asked on SO about where to place that XML, I was answered that this is a very old method of configuration and should not be used anymore.
What would be the "up-to-date" way to do this ?
#SpringBootApplication
public class So43983296Application implements CommandLineRunner {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(So43983296Application.class, args);
Thread.sleep(10_000);
context.close();
}
#Autowired
private DefaultTcpNetSSLSocketFactorySupport ssl;
#Override
public void run(String... args) throws Exception {
Socket socket = ssl.getSocketFactory().createSocket("localhost", 1234);
socket.getOutputStream().write("foo\r\n".getBytes());
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String result = br.readLine();
System.out.println(result);
br.close();
socket.close();
}
#Bean
public TcpNetServerConnectionFactory scf() {
TcpNetServerConnectionFactory scf = new TcpNetServerConnectionFactory(1234);
DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport = tcpSocketFactorySupport();
scf.setTcpSocketFactorySupport(tcpSocketFactorySupport);
// Add custom serializer/deserializer here; default is ByteArrayCrLfSerializer
return scf;
}
#Bean
public DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport() {
TcpSSLContextSupport sslContextSupport = new DefaultTcpSSLContextSupport("classpath:test.ks",
"classpath:test.truststore.ks", "secret", "secret");
DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport =
new DefaultTcpNetSSLSocketFactorySupport(sslContextSupport);
return tcpSocketFactorySupport;
}
#Bean
public TcpInboundGateway inGate() {
TcpInboundGateway inGate = new TcpInboundGateway();
inGate.setConnectionFactory(scf());
inGate.setRequestChannelName("upperCase");
return inGate;
}
#ServiceActivator(inputChannel = "upperCase")
public String upCase(byte[] in) {
return new String(in).toUpperCase();
}
}
If you prefer XML configuration for Spring Integration, add it to a spring configuration xml file and use #ImportResource("my-context.xml") on the class.
I want to connect to a web service in a SSL connection. I connect to it and I get Service and Port but when I send Requests, it just returns null.
I searched the web but I could not understand what is the problem. may be because it is SSL, I need to connect it different as an Http connection, is it true?
I used auto code generators, they return null too, WireShark says that SSL Packages transmitted correctly but I cannot read the SOAP from these packages because they are SSL.
I test the web service with some applications and the tools and got correct answers from them.
Question:
is it possible that the null value is because SSL connection?
what mistakes could make this null returning?
How can I see the SOAP messeges I send and I get?
Here is My Java Code:
public class WS_TheServeice
{
private static QName qname;
private static URL url;
private static Service service;
private static ImplementationServicePortType sender;
static
{
qname = new QName("http://wservice.com/", "ImplementationService");
try
{
url = new URL("https://to-service?wsdl");
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
service = Service.create(url, qname);
sender = service.getPort(ImplementationServicePortType.class);
}
public static boolean PayToAcceptor(int AcceptorID, int Kipa) throws Exception
{
getUserInfo req = new getUserInfo();
req.zpID = AcceptorID;
req.kipa = Kipa;
getUserInfoResponse user_info = new getUserInfoResponse();//user_info is not NULL here
user_info = sender.getUserInfo(req);//But web server makes it NULL
if (user_info!=null) //// ---- HERE, IT Always return NULL
{
System.out.println("YouWon");
return true;
}
else
{
System.out.println("YouLoose");
return false;
}
}
public static void main(String Args[]) throws Exception
{
PayToAcceptor(12345, 1);
}
}
thanks.
Did you figure out how to do this? I've had similar problems in the past..
Did you try this: SSL Connection for consuming web services ?
i need to perform the all operation like the creating the quartz-2 scheduler and deleting on only one Apache camel context
using restful service. when i try using following code .each time its creating the new context object. i do not know how to fix it or where i need to initiate the apache camel context object.
this is my code
this is my java restful services which is call to the quartz scheduler.
java Rest Services.
#Path("/remainder")
public class RemainderResource {
private static org.apache.log4j.Logger log = Logger.getLogger(RemainderResource.class);
RemainderScheduler remainderScheduler=new RemainderScheduler();
CamelContext context = new DefaultCamelContext();
#POST
#Path("/beforeday/{day}")
public void create(#PathParam("day") int day,final String userdata)
{
log.debug("the starting process of the creating the Remainder");
JSONObject data=(JSONObject) JSONSerializer.toJSON(userdata);
String cronExp=data.getString("cronExp");
remainderScheduler.create(cronExp,day,context);
}
}
This is my java class which is schedule job .
public class RemainderScheduler {
private static org.apache.log4j.Logger log = Logger.getLogger(RemainderScheduler.class);
public void sendRemainder(int day)
{
log.debug("the starting of the sending the Remainder to user");
}
public RouteBuilder createMyRoutes(final String cronExp,final int day)
{
return new RouteBuilder()
{
#Override
public void configure() throws Exception {
log.debug("Before set schedulling");
from("quartz2://RemainderGroup/Remainder? cron="+cronExp+"&deleteJob=true&job.name='RemainderServices'").bean(new RemainderScheduler(), "sendRemainder('"+day+"')").routeId("Remainder")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
}
})
;
log.debug("after set schedulling");
}
};
}
public void stopService(CamelContext context)
{
log.debug("this is going to be stop the route");
try {
context.stopRoute("Remainder");
context.removeRoute("Remainder");
} catch (Exception e) {
e.printStackTrace();
}
}
public void create(final String cronExp,final int day,CamelContext context)
{
try
{
//this for if all ready exist then stop it.
if(context.getRoute("Remainder")!=null)
stopService(context);
log.debug("the starting of the process for creating the Remaider Services");
context.addRoutes(createMyRoutes(cronExp, day));
context.start();
log.debug("the status for removing the services is"+context.removeRoute("Remainder"));
}
catch(Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
}
}
}
if i execute the above code then the each java Restful request create the new context object.
and its will start the job scheduling on new apache camel context object. and if send request for stop the route then also its creating the new apache context object so i am not able to reset or stop the quartz-2 scheduler.
It is not a good practise to create a camel context per request.
I suggest you to use camel-restlet or camel-cxfrs to delegate the request of create and delete scheduler to another camel context.