how to automatically init an object after jetty setup? - java

My java application starts a jetty server container.
Is there any "after init" method that jetty can call after it's up
that will construct a specific BL object and call one of its methods?
This is my code to init jetty:
public static void main(String[] args) throws Exception {
SdkServiceConfig.s.initLog();
logger.error("testing log");
final int port = 8083;
...
webappContext.setExtractWAR(false);
handlers.addHandler(webappContext);
// Adding the handlers to the server.
jettyServer.setHandler(handlers);
try {
jettyServer.start();
jettyServer.join();
} catch (Exception ex) {
logger.error("failed to init jetty server", ex);
System.out.println(ex);
throw new RuntimeException(ex);
} finally {
jettyServer.destroy();
}
}
and then i call specific url to trigger my server state initialization.
Server.java
#Path("/waitRequests")
#GET
#Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8")
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public void waitRequests() throws Exception {
System.out.println("waitRequests");
PubSubFactory pubSubFactory = new PubSubFactory();
pubSubFactory.init(SdkServiceConfig.s.GCP_PROJECT_ID, new File(SdkServiceConfig.s.SDK_PUBSUB_CLIENT_SECRET));
I wish it would be something like:
#Path("/sdk-service")
public class SdkOperation {
private final org.apache.log4j.Logger logger = LoggingUtils.getLogger();
private final CofmanService cofmanService;
// private SdkRequestRepo sdkRequestRepo;
private CustomPublisher resultPublisher;
public SdkOperation() throws Exception {
this(new CofmanServiceNet(), null);
}
Server server = new Server();
server.waitRequests()

Related

Run Spring Boot server and HttpServer on single application?

I have init method which starts HttpServer with controller:
public void init() {
GatewayServer server = new GatewayServer("some_host", 8080);
server.registerController(WorkshopOrderEndpoint.class);
ControllerFactory.createController();
server.startServer();
}
This is the GatewayServer.class:
public class GatewayServer {
private static Logger logger = LogManager.getFormatterLogger(GatewayServer.class);
private final String serverHost;
private final String serverPort;
private URI address;
private ResourceConfig resourceConfig = null;
private com.sun.net.httpserver.HttpServer server;
public GatewayServer(final String host, final Integer port) {
serverHost = host;
serverPort = String.valueOf(port);
try {
logger.info("HTTP: Create Http-Server.");
resourceConfig = new ResourceConfig();
address = new URI(String.format("http://%s:%s/", serverHost, serverPort));
} catch (URISyntaxException ex) {
logger.error("HTTP: %s", ex.getMessage());
LoggingHelper.sendExceptionLog(ex, "STATUS_URI_ERROR", "URI Encoding error.");
} catch (ProcessingException ex) {
logger.error("HTTP: %s", ex.getMessage());
LoggingHelper.sendExceptionLog(ex, "STATUS_HTTP_ERROR", "HTTP-Server start error.");
}
}
public void registerController(Class<?> controller) {
if (resourceConfig != null) {
logger.info("HTTP: Register Controller: %s", controller.getName());
resourceConfig.register(controller);
}
}
public void startServer() {
server = JdkHttpServerFactory.createHttpServer(address, resourceConfig, false);
logger.info("HTTP: Start Http-Server. Adress: %s", address);
server.start();
}
public void stopServer(int delay) {
logger.info("HTTP: Stop Http-Server. Address: %s", address);
server.stop(delay);
}
}
This is pure java application and I want to start Spring Server in order to run Eureka Server by adding this code to the init() method:
SpringRestApplication springRestApplication = new SpringRestApplication();
springRestApplication.start();
Where SpringRestApplication.class is starting the Spring Boot server:
#SpringBootApplication
#EnableEurekaServer
public class SpringRestApplication {
public void start() {
SpringApplication.run(SpringRestApplication.class, new String[0]);
}
}
I would to run two servers on same host but different ports is it possible to connect Spring Boot Tomcat server with HttpServer?
You can run the two on different ports.
Eugene shows a couple of options to change the port of the Spring Boot application: https://www.baeldung.com/spring-boot-change-port
This is the most straight-forward:
public void start() {
SpringApplication app = new SpringApplication(SpringRestApplication.class);
app.setDefaultProperties(Collections
.singletonMap("server.port", "8083"));
app.run(args);
}

How can the RMI registry be stopped programatically? [duplicate]

A RMI server which works fine without the stopServer functionality.
public class HelloServer extends UnicastRemoteObject implements HelloInterface
{
private final static int PORT=1102;
private final String serverName="server";
private Timer timer;
public HelloServer() throws RemoteException
{
timer = new Timer(); //At this line a new Thread will be created
timer.schedule(new StopServerTask(), 5000);
}
#Override
public String serverResponse(String request) throws RemoteException
{
return "Hello"+request;
}
public static void main(String[] args)
{
try
{
HelloServer skeleton=new HelloServer();
System.out.println("Starting server");
skeleton.startServer();
System.out.println("Server started");
}
catch (RemoteException ex)
{
ex.printStackTrace();
}
}
public void startServer()
{
try {
HelloServer skeleton=new HelloServer();
Registry reg=LocateRegistry.createRegistry(PORT);
reg.rebind(serverName, skeleton);
System.out.println("Server is ready");
} catch (RemoteException ex)
{
Logger.getLogger(HelloInterface.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void stopServer()
{
System.out.println("Stopping server");
try {
Registry rmiRegistry = LocateRegistry.getRegistry(PORT);
HelloInterface myService = (HelloInterface) rmiRegistry.lookup(serverName);
rmiRegistry.unbind(serverName);
UnicastRemoteObject.unexportObject(rmiRegistry, true);
} catch (NoSuchObjectException e)
{
e.printStackTrace();
} catch (NotBoundException e)
{
e.printStackTrace();
} catch (RemoteException ex) {
Logger.getLogger(HelloServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
class StopServerTask extends TimerTask
{
#Override
public void run()
{
stopServer();
}
}
}
Whenever stopServer() in invoked exception is thrown at
UnicastRemoteObject.unexportObject(rmiRegistry, true);
Here is the stack Trace
java.rmi.NoSuchObjectException: object not exported
at sun.rmi.transport.ObjectTable.unexportObject(ObjectTable.java:153)
at java.rmi.server.UnicastRemoteObject.unexportObject(UnicastRemoteObject.java:297)
at rmi.HelloServer.stopServer(HelloServer.java:84)
Things are same even when I clean the service object by using
UnicastRemoteObject.unexportObject(myService, true);
Could someone suggest a clean way to stop the server which also releases the port for reuse.
You need to store the result of LocateRegistry.createRegistry(), and unexport that. At present you're trying to unexport a stub.
I implemented a shutdown-service in my rmi-server. If I want to shut it down, I call it with a password. Simple Example:
public interface ShutdownInterface extends Remote {
public void shutdownService(String password) throws RemoteException;
}
The serverside implementation can look something like:
public class ShutdownService extends UnicastRemoteObject implements ShutdownInterface {
private static final long serialVersionUID = 1L;
private boolean doShutdown = false;
public ShutdownService() throws RemoteException {
super();
}
#Override
public void shutdownService(String password) throws RemoteException {
if ("abcde12345".equals(password)) {
System.out.println("shutdown requested.");
this.doShutdown = true;
} else {
System.out.println("wrong pwd for shutdown");
}
}
public boolean isDoShutdown() {
return this.doShutdown;
}
}
Now the server itself keeps a reference to this:
public class BackendServer {
public final static int RMI_PORT = 1974;
private Registry registry = null;
private ShutdownService shutdownService = null;
public BackendServer() throws RemoteException {
registry = LocateRegistry.createRegistry(RMI_PORT);
this.shutdownService = new ShutdownService();
}
public void initialize() throws AccessException, RemoteException, AlreadyBoundException {
shutdownService = new ShutdownService();
registry.bind("ShutdownService", shutdownService);
registry.bind("MyDataService", new MyDataService());
}
public void stop() throws NoSuchObjectException {
System.out.println("stopping rmi server.");
UnicastRemoteObject.unexportObject(registry, true);
System.exit(0);
}
public boolean shouldStop() {
return this.shutdownService.isDoShutdown();
}
public static void main(String args[]) {
try {
BackendServer bs = new BackendServer();
bs.initialize();
System.out.println("Server ready.");
while (!bs.shouldStop()) {
Thread.sleep(1000);
}
bs.stop();
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
Of course, this can be realized in a more beautiful way, but this should give you an idea of how to easily implement a shutdown yourself. You can call it from the main client or from a small commandline-tool you code for your server.

Multi threading JMX client

I am trying to implement a JMXclient to monitor remote JVM. I obtain the mbeanserver connection from a main method and pass it to a thread which search for memory usage. Problem is when I do this i get an error saying "The client has been closed". But if I run the program without threads it works perfectly.
public class ESBMonitor {
private static TreeSet<ObjectName> mbeansNames = null;
public static void main(String[] args) throws IOException {
RemoteConnector.defaultConnector();
MBeanServerConnection remote = RemoteConnector.getRemote();
//MemoryExtractor.getMemoryInfo();
MemoryExtractor memoryExtractor = new MemoryExtractor();
memoryExtractor.start();
RemoteConnector.closeConnection();
}
}
public class RemoteConnector {
private static MBeanServerConnection remote = null;
private static JMXConnector connector = null;
private static final Logger logger= LogManager.getLogger(RemoteConnector.class);
public static void defaultConnector() {
try {
JMXServiceURL target = new JMXServiceURL
("service:jmx:rmi://localhost:11111/jndi/rmi://localhost:9999/jmxrmi");
//for passing credentials for password
Map<String, String[]> env = new HashMap<String, String[]>();
String[] credentials = {"admin", "admin"};
env.put(JMXConnector.CREDENTIALS, credentials);
connector = JMXConnectorFactory.connect(target, env);
remote = connector.getMBeanServerConnection();
logger.info("MbeanServer connection obtained");
} catch (MalformedURLException e) {
logger.error(e.getStackTrace());
} catch (IOException e) {
logger.error(e.getStackTrace());
}
}
public static MBeanServerConnection getRemote() {
return remote;
}
public static synchronized Object getMbeanAttribute(ObjectName bean, String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException {
return remote.getAttribute(bean,attribute);
}
}
public class MemoryExtractor extends Thread{
final static Logger logger = Logger.getLogger(MemoryExtractor.class);
private static MBeanInfo memoryInfo;
private static ObjectName bean = null;
private static double MEMORY = 0.05;
private static long TIMEOUT = 3000;
public static void getMemoryInfo() {
try {
bean = new ObjectName("java.lang:type=Memory");
checkWarningUsage();
} catch (MalformedObjectNameException e) {
logger.error("MemoryExtractor.java:25 " + e.getMessage());
}
}
public static boolean checkWarningUsage() {
try {
logger.info("MemoryExtractor.java:46 Acessing memory details");
CompositeData memoryUsage = (CompositeData) RemoteConnector.getMbeanAttribute(bean,"HeapMemoryUsage");
} catch (Exception e) {
logger.error("MemoryExtractor.java:58 " + e.getMessage());
}
return false;
}
public void run(){
while (true){
getMemoryInfo();
}
}
}
No matter I synchronize or not problem will still be there.
Stack trace
java.io.IOException: The client has been closed.
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.restart(ClientCommunicatorAdmin.java:94)
at com.sun.jmx.remote.internal.ClientCommunicatorAdmin.gotIOException(ClientCommunicatorAdmin.java:54)
at javax.management.remote.rmi.RMIConnector$RMIClientCommunicatorAdmin.gotIOException(RMIConnector.java:1474)
at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.getAttribute(RMIConnector.java:910)
at org.wso2.connector.RemoteConnector.getMbeanAttribute(RemoteConnector.java:55)
at org.wso2.jvmDetails.MemoryExtractor.checkWarningUsage(MemoryExtractor.java:47)
at org.wso2.jvmDetails.MemoryExtractor.run(MemoryExtractor.java:79)
You are caching the reference to the JMXConnector as a static in your RemoteConnector class, so there's only ever one connection. As soon as the first thread closes that singleton connection, the next time any other thread attempts to call something it will fail because you've already closed the connection at that point.
If you want to have multiple threads, then either you should close the connection when all threads have finished, or have one connection per thread.

Java RMI with Callable

I have a server and several clients. The server should be able to delegate tasks to the clients so I tried to implement RMI. I followed this tutorial and everything is working fine if I use String as param- and/or return-value.
Now the server should send undefined tasks to the clients so I tried to use a Callable as param but the program crashed with a NotSerializableException. Since Callable doesn't implement the Serializeable interface thats the result I expected.
Now I found several sources that use Callable and Runnable as params and that confuses me. Is there any trick to get it to work? Or do i miss something important? Maybe theres a technology that fits better?
Resource1 S. 33
Resource2 s. 5
And heres my code:
// Client
public static void main(String[] args) throws InterruptedException {
App app = new App();
app.startClient();
Thread.sleep(20000);//just for test purpose
}
private void startClient() {
try {
// create on port 1099
Registry registry = LocateRegistry.createRegistry(1099);
// create a new service named myMessage
registry.rebind("calcClient", new CalculateRemoteImpl<String>());
} catch (RemoteException e) {
e.printStackTrace();
}
System.out.println("System is ready");
}
// RemoteInterface
public interface CalculateRemote<T> extends Remote {
public T hello(Callable<T> hello) throws RemoteException;
}
// RemoteInterfaceImpl
public class CalculateRemoteImpl<T> extends UnicastRemoteObject implements CalculateRemote<T> {
public T hello(Callable<T> hello) throws RemoteException {
return (T) ("Hello " + hello);// just print address of object
}
}
.
// Server
public static void main(String[] args) {
App app = new App();
app.doTest();
}
private void doTest() {
try {
// fire to localhost port 1099
Registry myRegistry = LocateRegistry.getRegistry("127.0.0.1", 1099);
// search for myMessage service
CalculateRemote<String> impl = (CalculateRemote<String>) myRegistry.lookup("calcClient");
// call server's method
System.out.println("Message: " + impl.hello(new Callable<String>() {
public String call() throws RemoteException, Exception {
return "hello";
}
}));
System.out.println("Message Sent");
} catch (NotBoundException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
// And the same RemoteInterface
public interface CalculateRemote<T> extends Remote {
public T hello(Callable<T> hello) throws RemoteException;
}
.
// stacktrace
java.rmi.MarshalException: error marshalling arguments; nested exception is:
java.io.NotSerializableException: de.fhb.rmicalcserver.App$1
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:156)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at $Proxy0.hello(Unknown Source)
at de.fhb.rmicalcserver.App.doTest(App.java:30)
at de.fhb.rmicalcserver.App.main(App.java:18)
Caused by: java.io.NotSerializableException: de.fhb.rmicalcserver.App$1
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:292)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:151)
If you want to send objects to clients whose classes aren't deployed at the client you need to take a long look at the RMI codebase feature.

Apache Tomcat Simple Comet Servlet

I'm trying create very simple Comet Servlet which will push Hello World message to subscribers:
#WebServlet("/ChatServlet")
public class ChatServlet extends HttpServlet implements CometProcessor {
private static final long serialVersionUID = 1L;
private MessageSender messageSender = null;
private static final Integer TIMEOUT = 60 * 1000;
public void init(ServletConfig config) throws ServletException {
messageSender = new MessageSender();
Thread messageSenderThread =
new Thread(messageSender);
messageSenderThread.setDaemon(true);
messageSenderThread.start();
}
public void destroy() {
// messageSender.stop();
messageSender = null;
}
#Override
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
System.out.println("Begin for session: " + request.getSession(true).getId());
messageSender.setConnection(response);
}
else if (event.getEventType() == CometEvent.EventType.ERROR) {
System.out.println("Error for session: " + request.getSession(true).getId());
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
System.out.println("End for session: " + request.getSession(true).getId());
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
throw new UnsupportedOperationException("This servlet does not accept data");
}
}
}
and then my Runnable looks like this:
public class MessageSender implements Runnable {
protected boolean running = true;
protected final List<String> messages = new ArrayList<String>();
private ServletResponse connection;
public synchronized void setConnection(ServletResponse connection){
this.connection = connection;
notify();
}
#Override
public void run() {
while (running) {
if (messages.size() == 0) {
try {
synchronized (messages) {
messages.wait();
}
} catch (InterruptedException e) {
// Ignore
}
}
String[] pendingMessages = null;
synchronized (messages) {
pendingMessages = messages.toArray(new String[0]);
messages.clear();
}
try {
if (connection == null){
try{
synchronized(this){
wait();
}
} catch (InterruptedException e){
// Ignore
}
}
PrintWriter writer = connection.getWriter();
writer.println("hello World");
System.out.println("Writing Hello World");
writer.flush();
writer.close();
connection = null;
System.out.println("Closing connection");
} catch (IOException e) {
System.out.println("IOExeption sending message"+e.getMessage());
}
}
}
}
now my Dojo cometd code looks like this:
<script src="dojo/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojox.cometd");
dojo.addOnLoad(function(){
dojox.cometd.init("ChatServlet");
dojox.cometd.subscribe("ChatServlet", window, "alertMessage");
});
function alertMessage(message) {
alert("Message: " + message);
}
</script>
Now when I load client I'm getting the following error:
Begin for session: C898A372F1B1199C04CA308F715ABC36Nov 6, 2011 2:00:48 PM org.apache.catalina.core.StandardWrapperValve event
SEVERE: Servlet.service() for servlet [com.vanilla.servlet.ChatServlet] in context with path [/Servlet3Comet] threw exception
java.lang.UnsupportedOperationException: This servlet does not accept data
at com.vanilla.servlet.ChatServlet.event(ChatServlet.java:75)
Error for session: C898A372F1B1199C04CA308F715ABC36
End for session: C898A372F1B1199C04CA308F715ABC36
What am I doing wrong?
Why does cometD subscription invokes CometEvent.EventType.READ?
Does anybody have any working comet example?
P.S: I did switch to Nio according to Tomcat configuration.
Documentation for init(ServletConfig):
public void init(ServletConfig config) throws ServletException Called
by the servlet container to indicate to a servlet that the servlet is
being placed into service.
See Servlet#init. This implementation stores the ServletConfig object
it receives from the servlet container for later use. When overriding
this form of the method, call super.init(config).
And Documentation for init():
public void init() throws ServletException A convenience method which
can be overridden so that there's no need to call super.init(config).
Instead of overriding init(ServletConfig), simply override this method
and it will be called by GenericServlet.init(ServletConfig config).
The ServletConfig object can still be retrieved via
getServletConfig().
When overriding init(ServletConfig), your first call must be super.init(config);

Categories