Publish and stop endpoint web service in Java - java

I am trying to start/stop an Endpoint web service in a separate thread from my main program with the click of a button. Starting works fine, i am able to access all my WebMethods without issue. The problem is, when i click the stop button to try and stop the web service endpoint, i get an exception and i don't know what it is. I am new to Java as well.
Thanks in advance.
Excetion thrown at 'ep.stop()':
WebService Running On: http://0.0.0.0:9898/
Exception in thread "Thread-0" java.lang.NullPointerException
at com.sun.xml.internal.ws.transport.http.server.ServerMgr.removeContext(Unknown Source)
at com.sun.xml.internal.ws.transport.http.server.HttpEndpoint.stop(Unknown Source)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.stop(Unknown Source)
at com.simba.Server.startWebSrv(Server.java:27)
at com.simba.Server.run(Server.java:13)
Server class:
import javax.xml.ws.Endpoint;
public class Server extends Thread {
public volatile boolean active = true;
private Endpoint ep;
private String ip = "0.0.0.0";
public void run(){
ep = Endpoint.publish("http://" + ip + ":9898/", new SWS());
startWebSrv();
}
private void startWebSrv(){
synchronized(this){
try {
while (active) {
System.out.println("WebService Running On: http://" + ip + ":9898/");
wait();
}
}catch (InterruptedException e) {
e.printStackTrace();
}finally{
if(!active){
ep.stop();
System.out.println("WebService Stopped!");
}
}
}
}
}
How i am attempting to stop the service/thread from my main program:
MenuItem mntmToggleWebservice = new MenuItem(menu_4, SWT.NONE);
mntmToggleWebservice.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
synchronized(srv){
srv.active = false;
srv.notifyAll();
}
}
});
mntmToggleWebservice.setText("Toggle WebService");

Problem solved!
Don't use '0.0.0.0'. For some reason, creating the service on '0.0.0.0' works (uses the machine's actual ip), but Endpoint.stop() doesn't not play well with it.
Instead I just used 'System.getEvn('COMPUTERNAME')' and create the service with the machine name.

You can use the "input" to block the run of program
public class ServiceMain {
private static void DoNothing() {
}
public static void main(String[] args) {
String address = "http://127.0.0.1:7775/hb";
Endpoint ep = Endpoint.publish(address, new ServiceImp());
Scanner scanIn=new Scanner(System.in);
System.out.println("Web Service Release Successfully!");
while(!scanIn.next().equals("stop")){
DoNothing();
}
scanIn.close();
ep.stop();
System.out.println("Web Service Close Successfully!");
}
}

Related

Which Part of the RMI Server be implemented with multithreading

I've just started RMI programming recently and had complete most of the parts for the assignment requirements. But there was this question in my head where one of the requirements is supporting multiple threads. Basically in which part should the multi thread be implemented?
Should I make the Server class Runnable or make the objects that are being created in the Server class Runnable?
Here's the code of my Server class:
public class Server {
public static void main(String args[]) {
String portNum = "4444";
try {
Account_Server_Controller accountController = new Account_Server_Controller();
BookCategory_Server_Controller categoryController = new BookCategory_Server_Controller();
Book_Server_Controller bookController = new Book_Server_Controller();
BookActivity_Server_Controller bookActivityController = new BookActivity_Server_Controller();
startRegistry(Integer.parseInt(portNum));
Naming.rebind(ServerLocater.getAccountRegistryURL(), accountController);
Naming.rebind(ServerLocater.getBookRegistryURL(), bookController);
Naming.rebind(ServerLocater.getCategoryRegistryURL(), categoryController);
Naming.rebind(ServerLocater.getBookActivityRegistryURL(), bookActivityController);
System.out.println("Server is Ready.");
} catch (NumberFormatException | MalformedURLException | RemoteException e) {
System.out.println("Exception in Server.main: " + e);
}
}
private static void startRegistry(int rmiPortNum) throws RemoteException {
try {
Registry registry = LocateRegistry.getRegistry(rmiPortNum);
registry.list();
} catch (RemoteException ex) {
System.out.println("RMI registry is not located at port " + rmiPortNum);
Registry registry = LocateRegistry.createRegistry(rmiPortNum);
System.out.println("RMI registry created at port " + rmiPortNum);
}
}
}
No. You don't have to start any threads or implement any Runnables.
You just have to make sure that your remote method implementations are thread-safe.

Cling with tomcat

I am trying to create a service to autodiscover upnp devices in my local network, implementing it in a webapplication running on tomcat 7 and using 4thline Cling library.
I got this error
org.fourthline.cling.transport.RouterImpl handleStartFailure
SEVERE: Unable to initialize network router: org.fourthline.cling.transport.spi.InitializationException: Failed to set modified URLStreamHandlerFactory in this environment. Can't use bundled default client based on HTTPURLConnection, see manual.
In the cling's manual they say that Cling couldn't use the Java JDK's HTTPURLConnection for HTTP client operations. They suggest to configure network transport.
I didn't understand well how to do. Anyone had a similar problem?
Can you suggest me an example?
Thanks.
The code I am using is:
public class Example {
public static void startDiscovery() {
RegistryListener listener = new RegistryListener() {
public void remoteDeviceDiscoveryStarted(Registry registry,RemoteDevice device) {
String name = device.getDisplayString();
String url = device.getDetails().getBaseURL().toString();
String friendlyName = device.getDetails().getFriendlyName();
}
public void remoteDeviceDiscoveryFailed(Registry registry,RemoteDevice device, Exception ex) {
}
public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
}
public void remoteDeviceUpdated(Registry registry,RemoteDevice device) {
}
public void remoteDeviceRemoved(Registry registry,RemoteDevice device) {
}
public void localDeviceAdded(Registry registry, LocalDevice device) {
}
public void localDeviceRemoved(Registry registry, LocalDevice device) {
}
public void beforeShutdown(Registry registry) {
}
public void afterShutdown() {
}
};
try{
UpnpService upnpService = new UpnpServiceImpl(listener);
upnpService.getControlPoint().search(new STAllHeader());
// wait 5 seconds for them to respond
Thread.sleep(5000);
upnpService.shutdown();
}catch(Exception e){
e.printStackTrace();
}
}
}

Jersey SSE - eventOutput.write throws nullpointer after first message is sent

I have implemented a Restful web interface using Jersey for sending messages received from an internal JMS publisher to external clients via HTTP. I have managed to get a test message out to a Java client, but the Thread throws a null pointer exception before completing the write() execution, closing the connection and preventing further communication.
Here is my resource class:
#GET
#Path("/stream_data")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getServerSentEvents(#Context ServletContext context){
final EventOutput eventOutput = new EventOutput();
new Thread( new ObserverThread(eventOutput, (MService) context.getAttribute("instance")) ).start();
return eventOutput;
}
And here is my thread's run method:
public class ObserverThread implements Observer, Runnable {
//constructor sets eventOutput & mService objects
//mService notifyObservers() called when JMS message received
//text added to Thread's message queue to await sending to client
public void run() {
try {
String message = "{'symbol':'test','entryType'='0','price'='test'}";
Thread.sleep(1000);
OutboundEvent.Builder builder = new OutboundEvent.Builder();
builder.mediaType(MediaType.APPLICATION_JSON_TYPE);
builder.data(String.class, message);
OutboundEvent event = builder.build();
eventOutput.write(event);
System.out.println(">>>>>>SSE CLIENT HAS BEEN REGISTERED!");
mService.addObserver(this);
while(!eventOutput.isClosed()){
if(!updatesQ.isEmpty()){
pushUpdate(updatesQ.dequeue());
}
}
System.out.println("<<<<<<<SSE CLIENT HAS BEEN DEREGISTERED!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Here is my client code:
Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
WebTarget target = client.target(url);
EventInput eventInput = target.request().get(EventInput.class);
try {
while (!eventInput.isClosed()) {
eventInput.setChunkType(MediaType.WILDCARD_TYPE);
final InboundEvent inboundEvent = eventInput.read();
if (inboundEvent != null) {
String theString = inboundEvent.readData();
System.out.println(theString + "\n");
}
}
} catch (Exception e) {
e.printStackTrace();
}
I am getting the "{'symbol':'test','entryType'='0','price'='test'}" test message printed to the client console, but the server then prints a NullPointerException before it can print the ">>>>SSE Client registered" message. This closes the connection so the client exits the while loop and stops listening for updates.
I converted the project to a webapp 3.0 version facet in order to add an async-supported tag to the web.xml but i am receiving the same null pointer error. I am inclined to think that it is caused by the servlet ending the Request/Response objects once the first message is returned, evidence is shown in the stack trace:
Exception in thread "Thread-20" java.lang.NullPointerException
at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:741)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:434)
at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:299)
at org.apache.coyote.http11.Http11Processor.action(Http11Processor.java:981)
at org.apache.coyote.Response.action(Response.java:183)
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:314)
at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:288)
at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:98)
at org.glassfish.jersey.message.internal.CommittingOutputStream.flush(CommittingOutputStream.java:292)
at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:241)
at org.glassfish.jersey.server.ChunkedOutput$1.call(ChunkedOutput.java:192)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:242)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:345)
at org.glassfish.jersey.server.ChunkedOutput.flushQueue(ChunkedOutput.java:192)
at org.glassfish.jersey.server.ChunkedOutput.write(ChunkedOutput.java:182)
at com.bpc.services.service.ObserverThread.run(MarketObserverThread.java:32)
at java.lang.Thread.run(Thread.java:745)
<<<<<<<SSE CLIENT HAS BEEN DEREGISTERED!
I have attempted to test an sse broadcaster as well. In this case I am not seeing any exceptions thrown, but the connection is closed once the first message has been received, leading me to believe it is something in the servlet forcing the connection to close. Can anyone advise me on how to debug this on the server-side?
I had a similar issue from what seems to be a long standing bug in Jersey's #Context injection for ExecutorService instances. In their current implementation of Sse (version 2.27),
class JerseySse implements Sse {
#Context
private ExecutorService executorService;
#Override
public OutboundSseEvent.Builder newEventBuilder() {
return new OutboundEvent.Builder();
}
#Override
public SseBroadcaster newBroadcaster() {
return new JerseySseBroadcaster(executorService);
}
}
the executorService field is never initialized, so the JerseySseBroadcaster raises a NullPointerException in my case. I worked around the bug by explicitly triggering the injection.
If you're using HK2 for CDI (Jersey's default), a rough sketch of a solution to the question above could look similar to the following:
#Singleton
#Path("...")
public class JmsPublisher {
private Sse sse;
private SseBroadcaster broadcaster;
private final ExecutorService executor;
private final BlockingQueue<String> jmsMessageQueue;
...
#Context
public void setSse(Sse sse, ServiceLocator locator) {
locator.inject(sse); // Inject sse.executorService
this.sse = sse;
this.broadcaster = sse.newBroadcaster();
}
...
#GET
#Path("/stream_data")
#Produces(MediaType.SERVER_SENT_EVENTS)
public void register(SseEventSink eventSink) {
broadcaster.register(eventSink);
}
...
#PostConstruct
private void postConstruct() {
executor.submit(() -> {
try {
while(true) {
String message = jmsMessageQueue.take();
broadcaster.broadcast(sse.newEventBuilder()
.mediaType(MediaType.APPLICATION_JSON_TYPE)
.data(String.class, message)
.build());
}
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
#PreDestroy
private void preDestroy() {
executor.shutdownNow();
}
}

Server RMI stop automatically when I start it

I'm frensh so sorry for my english.
I'm trying to start a server rmi but the application stop whitout error :
Here my code:
public class Server {
public static void main(String[] args) {
try {
RemoteFunction skeleton = (RemoteFunction) UnicastRemoteObject.exportObject(new FunctionImpl(), 0);
int port = Integer.parseInt(Jndiprop.getString("port"));
Registry registry = LocateRegistry.createRegistry(port);
registry.rebind(Jndiprop.getString("url"), skeleton);
System.out.println("Rmi start");
} catch (Exception e) {
e.printStackTrace();
}
}
}
the port and the url are ok.
Someone can help me ?
You must store the Registry in a static variable. Otherwise it can be garbage-collected, which leads to a train of events that allows the whole JVM to exit.

ChannelHandlerContext.attr is not accessible from inside userEventTriggered

I am using netty for developing my server.
I am also implementing the Idle state handling in netty.
I got it working but an issue I recently found out.
I can't access the channel context attributes inside the userEventTriggered method.
here is my code and can anybody tell me why it is not possible.
I am setting it like
public static final AttributeKey<Agent> CLIENT_MAPPING = AttributeKey.valueOf("clientMapping");
...
ctx.attr(CLIENT_MAPPING).set(agent);
and inside handler, I am getting the value like (this is working perfectly)
Agent agent = ctx.attr(CLIENT_MAPPING).get();
But inside userEventTriggered it is returning null. (I am sure that it is set before this function is being called.)
public class Server
{
...
public void run() throws Exception
{
...
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).
channel(NioServerSocketChannel.class).
childHandler(new SslServerInitializer());
...
}
}
class SslServerInitializer extends ChannelInitializer<SocketChannel>
{
#Override
public void initChannel(SocketChannel ch) throws Exception
{
ChannelPipeline pipeline = ch.pipeline();
....
pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, Integer.parseInt(Main.configurations.get("netty.idleTimeKeepAlive.ms"))));
pipeline.addLast("idleTimeHandler", new ShelloidIdleTimeHandler());
}
}
class ShelloidIdleTimeHandler extends ChannelDuplexHandler
{
#Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
{
if (evt instanceof IdleStateEvent)
{
try
{
// This I am getting null, but I confirmed that I set the attribute from my handler and is accessible inside handler.
Agent agt = ctx.attr(WebSocketSslServerHandler.CLIENT_MAPPING).get();
ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"PING\", \"userId\": \"" + agt.getUserId() + "\"}"));
}
catch (Exception ex)
{
ctx.disconnect();
ex.printStackTrace();
}
}
}
}
Are you sure you set and get it in the same ChannelHandler? If you want to set and get it in different ChannelHandler you need to use Channel.attr(...)

Categories

Resources