Can someone please provide me very simple example of websocket client using javax.websocket?
I want to connect to websocket (ws://socket.example.com:1234), send message (add channel) and listen to messages. All messages (sent & listened) are in JSON format.
And btw is this library the best for simple websocket communication?
I've found a great example using javax.websocket here:
http://www.programmingforliving.com/2013/08/jsr-356-java-api-for-websocket-client-api.html
Here the code based on the example linked above:
TestApp.java:
package testapp;
import java.net.URI;
import java.net.URISyntaxException;
public class TestApp {
public static void main(String[] args) {
try {
// open websocket
final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(new URI("wss://real.okcoin.cn:10440/websocket/okcoinapi"));
// add listener
clientEndPoint.addMessageHandler(new WebsocketClientEndpoint.MessageHandler() {
public void handleMessage(String message) {
System.out.println(message);
}
});
// send message to websocket
clientEndPoint.sendMessage("{'event':'addChannel','channel':'ok_btccny_ticker'}");
// wait 5 seconds for messages from websocket
Thread.sleep(5000);
} catch (InterruptedException ex) {
System.err.println("InterruptedException exception: " + ex.getMessage());
} catch (URISyntaxException ex) {
System.err.println("URISyntaxException exception: " + ex.getMessage());
}
}
}
WebsocketClientEndpoint.java:
package testapp;
import java.net.URI;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
/**
* ChatServer Client
*
* #author Jiji_Sasidharan
*/
#ClientEndpoint
public class WebsocketClientEndpoint {
Session userSession = null;
private MessageHandler messageHandler;
public WebsocketClientEndpoint(URI endpointURI) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, endpointURI);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Callback hook for Connection open events.
*
* #param userSession the userSession which is opened.
*/
#OnOpen
public void onOpen(Session userSession) {
System.out.println("opening websocket");
this.userSession = userSession;
}
/**
* Callback hook for Connection close events.
*
* #param userSession the userSession which is getting closed.
* #param reason the reason for connection close
*/
#OnClose
public void onClose(Session userSession, CloseReason reason) {
System.out.println("closing websocket");
this.userSession = null;
}
/**
* Callback hook for Message Events. This method will be invoked when a client send a message.
*
* #param message The text message
*/
#OnMessage
public void onMessage(String message) {
if (this.messageHandler != null) {
this.messageHandler.handleMessage(message);
}
}
#OnMessage
public void onMessage(ByteBuffer bytes) {
System.out.println("Handle byte buffer");
}
/**
* register message handler
*
* #param msgHandler
*/
public void addMessageHandler(MessageHandler msgHandler) {
this.messageHandler = msgHandler;
}
/**
* Send a message.
*
* #param message
*/
public void sendMessage(String message) {
this.userSession.getAsyncRemote().sendText(message);
}
/**
* Message handler.
*
* #author Jiji_Sasidharan
*/
public static interface MessageHandler {
public void handleMessage(String message);
}
}
TooTallNate has a simple client side https://github.com/TooTallNate/Java-WebSocket
Just add the java_websocket.jar in the dist folder into your project.
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_10;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONException;
import org.json.JSONObject;
WebSocketClient mWs = new WebSocketClient( new URI( "ws://socket.example.com:1234" ), new Draft_10() )
{
#Override
public void onMessage( String message ) {
JSONObject obj = new JSONObject(message);
String channel = obj.getString("channel");
}
#Override
public void onOpen( ServerHandshake handshake ) {
System.out.println( "opened connection" );
}
#Override
public void onClose( int code, String reason, boolean remote ) {
System.out.println( "closed connection" );
}
#Override
public void onError( Exception ex ) {
ex.printStackTrace();
}
};
//open websocket
mWs.connect();
JSONObject obj = new JSONObject();
obj.put("event", "addChannel");
obj.put("channel", "ok_btccny_ticker");
String message = obj.toString();
//send message
mWs.send(message);
// and to close websocket
mWs.close();
Have a look at this Java EE 7 examples from Arun Gupta.
I forked it on github.
Main
/**
* #author Arun Gupta
*/
public class Client {
final static CountDownLatch messageLatch = new CountDownLatch(1);
public static void main(String[] args) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
String uri = "ws://echo.websocket.org:80/";
System.out.println("Connecting to " + uri);
container.connectToServer(MyClientEndpoint.class, URI.create(uri));
messageLatch.await(100, TimeUnit.SECONDS);
} catch (DeploymentException | InterruptedException | IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
ClientEndpoint
/**
* #author Arun Gupta
*/
#ClientEndpoint
public class MyClientEndpoint {
#OnOpen
public void onOpen(Session session) {
System.out.println("Connected to endpoint: " + session.getBasicRemote());
try {
String name = "Duke";
System.out.println("Sending message to endpoint: " + name);
session.getBasicRemote().sendText(name);
} catch (IOException ex) {
Logger.getLogger(MyClientEndpoint.class.getName()).log(Level.SEVERE, null, ex);
}
}
#OnMessage
public void processMessage(String message) {
System.out.println("Received message in client: " + message);
Client.messageLatch.countDown();
}
#OnError
public void processError(Throwable t) {
t.printStackTrace();
}
}
Use this library org.java_websocket
First thing you should import that library in build.gradle
repositories {
mavenCentral()
}
then add the implementation in dependency{}
implementation "org.java-websocket:Java-WebSocket:1.3.0"
Then you can use this code
In your activity declare object for Websocketclient like
private WebSocketClient mWebSocketClient;
then add this method for callback
private void ConnectToWebSocket() {
URI uri;
try {
uri = new URI("ws://your web socket url");
} catch (URISyntaxException e) {
e.printStackTrace();
return;
}
mWebSocketClient = new WebSocketClient(uri) {
#Override
public void onOpen(ServerHandshake serverHandshake) {
Log.i("Websocket", "Opened");
mWebSocketClient.send("Hello from " + Build.MANUFACTURER + " " + Build.MODEL);
}
#Override
public void onMessage(String s) {
final String message = s;
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView textView = (TextView)findViewById(R.id.edittext_chatbox);
textView.setText(textView.getText() + "\n" + message);
}
});
}
#Override
public void onClose(int i, String s, boolean b) {
Log.i("Websocket", "Closed " + s);
}
#Override
public void onError(Exception e) {
Log.i("Websocket", "Error " + e.getMessage());
}
};
mWebSocketClient.connect();
}
I have Spring 4.2 in my project and many SockJS Stomp implementations usually work well with Spring Boot implementations. This implementation from Baeldung worked(for me without changing from Spring 4.2 to 5). After Using the dependencies mentioned in his blog, it still gave me ClassNotFoundError. I added the below dependency to fix it.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
Here is such a solution from - com.neovisionary.ws.client.Web socket - https://github.com/TakahikoKawasaki/nv-websocket-client
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import com.neovisionaries.ws.client.WebSocketFrame;
public class WssM {
public static List<String> ListMessage = new ArrayList<>();
public static boolean WebSocketLog = true;
public static final String WssURL = "wss://site.com/api/sport_tree_ws/v1";
public static final String WebsocketMessage = "{\"type\": \"subscribe_state\", \"subscribe_state\": {\"uid\": \"-1\"}}";
public static void main(String[] args) throws IOException, WebSocketException {
WebSocket socket = connect(WssURL);
BufferedReader in = getInput();
socket.sendText(WebsocketMessage);
String text;
try {
while ((text = in.readLine()) != null) {
if (text.equals("exit")) break;
if (!socket.isOpen()) {
System.out.println("Socket is closed. Trying to reconnect...");
socket.recreate().connect();
System.out.println("Reconnected!");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket.isOpen()) {
System.out.println("Disconnecting connection to server!");
socket.disconnect(); //Close the WebSocket.
}
}
}
private static WebSocket connect(String Host) throws IOException, WebSocketException {
WebSocketFactory wsFactory = new WebSocketFactory().setConnectionTimeout(55000);
WebSocket socket = wsFactory.createSocket(URI.create(Host)).addProtocol("json");//.addHeader("Sec-WebSocket-Protocol", "json")
//WebSocket socket = wsFactory.createSocket(URI.create(HOST + "?Authorization=" + DUMMY_JWT_TOKEN));
socket.addListener(new WebSocketAdapter() {
#Override
public void onSendingHandshake(WebSocket websocket, String requestLine, List<String[]> headers) {
if (WebSocketLog) System.out.println(requestLine);
for (String[] header : headers) { //Print the header, "{name}: {value}"
if (WebSocketLog) System.out.format("%s: %s\n", header[0], header[1]);
}
}
#Override
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) {
if (WebSocketLog) System.out.println("Success! WebSocket - Connected!");
}
#Override
public void onTextMessage(WebSocket websocket, String text) {
if (WebSocketLog) System.out.printf("MessageToClient: %s%n", text); ListMessage.add(text);
}
#Override
public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) {
if (WebSocketLog) System.out.println("Disconnecting...");
if (WebSocketLog) System.out.printf(" Opcode: %d%n", serverCloseFrame.getOpcode());
}
#Override
public void onPongFrame(WebSocket websocket, WebSocketFrame frame) {
if (WebSocketLog) System.out.printf("Received some pong..!! Payload text: %s%n", frame.getPayloadText());
System.out.printf(" Opcode: %d%n", frame.getOpcode());
}
#Override
public void onPingFrame(WebSocket websocket, WebSocketFrame frame) {
if (WebSocketLog) System.out.printf("I have been pinged by server at %s%n", LocalDateTime.now());
websocket.sendPong("Ponging from client");
}
#Override
public void onTextFrame(WebSocket websocket, WebSocketFrame frame) {
if (WebSocketLog) System.out.printf("onTextFrame - %s%n", LocalDateTime.now());
websocket.sendPong("onTextFrame from client");
}
#Override
public void onError(WebSocket websocket, WebSocketException cause) {
System.out.printf("I have received exception %s%n", cause.getMessage());
}
}).connect();
return socket;
}
private static BufferedReader getInput() {
return new BufferedReader(new InputStreamReader(System.in));
}
}
Related
When I'm running a Java WebSocketStompClient, I got below error:
org.eclipse.jetty.websocket.api.MessageTooLargeException: Text message size [73728] exceeds maximum size [65536]
Sample code:
import org.apache.log4j.Logger;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import org.springframework.web.socket.sockjs.frame.Jackson2SockJsMessageCodec;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class HelloClient {
private static Logger logger = Logger.getLogger(HelloClient.class);
StompSession session;
private final static WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
public ListenableFuture<StompSession> connect() {
Transport webSocketTransport = new WebSocketTransport(new StandardWebSocketClient());
List<Transport> transports = Collections.singletonList(webSocketTransport);
SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.setMessageCodec(new Jackson2SockJsMessageCodec());
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
long[] hb = stompClient.getDefaultHeartbeat();
boolean en = stompClient.isDefaultHeartbeatEnabled();
long timeout = stompClient.getReceiptTimeLimit();
String url = "https://www.test.com";
return stompClient.connect(url, headers, new MyHandler());
}
public void subscribeMsg(StompSession stompSession) throws ExecutionException, InterruptedException {
stompSession.subscribe("/topic/test", new StompFrameHandler() {
public Type getPayloadType(StompHeaders stompHeaders) {
return byte[].class;
}
public void handleFrame(StompHeaders stompHeaders, Object o) {
logger.info("Received message " + new String((byte[]) o));
String response = new String((byte[]) o);
}
});
}
private class MyHandler extends StompSessionHandlerAdapter {
public void afterConnected(StompSession stompSession, StompHeaders stompHeaders) {
logger.info("Now connected");
session = stompSession;
}
}
public boolean isConnected() {
try {
Thread.sleep(500);
return session != null && session.isConnected();
} catch (Exception e) {
logger.warn("Error happens when checking connection status, ", e);
return false;
}
}
public static void main(String[] args) throws Exception {
HelloClient helloClient = new HelloClient();
ListenableFuture<StompSession> f = helloClient.connect();
StompSession stompSession = f.get();
helloClient.subscribeMsg(stompSession);
while (true) {
if (!helloClient.isConnected()) {
logger.info("wss diconnected ");
logger.info("need re-create ");
}
}
}
}
How to increase the limitation for a Java stomp websocket client? I found some not related answers How can I set max buffer size for web socket client(Jetty) in Java which are not suitable for stomp websocket client.
Also tried stompClient.setInboundMessageSizeLimit(Integer.MAX_VALUE); which doesn't work.
I am trying to receive an http request using non-blocking io, then make another http request to another server using non-blocking io, and return some response, here is the code for my servlet:
package learn;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import javax.servlet.AsyncContext;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
#WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncProcessing extends HttpServlet {
private static final long serialVersionUID = -535924906221872329L;
public CompletableFuture<String> readRequestAsync(final HttpServletRequest req) {
final CompletableFuture<String> request = new CompletableFuture<>();
final StringBuilder httpRequestData = new StringBuilder();
try (ServletInputStream inputStream = req.getInputStream()){
inputStream.setReadListener(new ReadListener() {
final int BUFFER_SIZE = 4*1024;
final byte buffer[] = new byte[BUFFER_SIZE];
#Override
public void onError(Throwable t) {
request.completeExceptionally(t);
}
#Override
public void onDataAvailable() {
if(inputStream.isFinished()) return;
System.out.println("----------------------------------------");
System.out.println("onDataAvailable: " + Thread.currentThread().getName());
try {
while(inputStream.isReady()) {
int length = inputStream.read(buffer);
httpRequestData.append(new String(buffer, 0, length));
}
} catch (IOException ex) {
request.completeExceptionally(ex);
}
}
#Override
public void onAllDataRead() throws IOException {
try {
request.complete(httpRequestData.toString());
}
catch(Exception e) {
request.completeExceptionally(e);
}
}
});
} catch (IOException e) {
request.completeExceptionally(e);
}
return request;
}
private Client createAsyncHttpClient() {
ResteasyClientBuilder restEasyClientBuilder = (ResteasyClientBuilder)ClientBuilder.newBuilder();
return restEasyClientBuilder.useAsyncHttpEngine().connectTimeout(640, TimeUnit.SECONDS).build();
}
public CompletableFuture<Response> process(String httpRequest){
System.out.println("----------------------------------------");
System.out.println("process: " + Thread.currentThread());
CompletableFuture<Response> futureResponse = new CompletableFuture<>();
Client client = createAsyncHttpClient();
client.target("http://localhost:3000").request().async().get(new InvocationCallback<Response>() {
#Override
public void completed(Response response) {
System.out.println("----------------------------------------");
System.out.println("completed: " + Thread.currentThread());
futureResponse.complete(response);
}
#Override
public void failed(Throwable throwable) {
System.out.println(throwable);
futureResponse.completeExceptionally(throwable);
}
});
return futureResponse;
}
public CompletableFuture<Integer> outputResponseAsync(Response httpResponseData, HttpServletResponse resp){
System.out.println("----------------------------------------");
System.out.println("outputResponseAsync: " + Thread.currentThread().getName());
CompletableFuture<Integer> total = new CompletableFuture<>();
try (ServletOutputStream outputStream = resp.getOutputStream()){
outputStream.setWriteListener(new WriteListener() {
#Override
public void onWritePossible() throws IOException {
System.out.println("----------------------------------------");
System.out.println("onWritePossible: " + Thread.currentThread().getName());
outputStream.print(httpResponseData.getStatus());
total.complete(httpResponseData.getLength());
}
#Override
public void onError(Throwable t) {
System.out.println(t);
total.completeExceptionally(t);
}
});
} catch (IOException e) {
System.out.println(e);
total.completeExceptionally(e);
}
return total;
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("----------------------------------------");
System.out.println("doGet: " + Thread.currentThread().getName());
final AsyncContext asyncContext = req.startAsync();
readRequestAsync(req)
.thenCompose(this::process)
.thenCompose(httpResponseData -> outputResponseAsync(httpResponseData, resp))
.thenAccept(a -> asyncContext.complete());
}
}
The server at http://localhost:3000 is an http server written in node which just returns a response after 27 seconds, i would like to make a request to the node server and while this request is being processed i would want to make another http request to the servlet to see if the same thread is being used. Currently i'm trying to use payara 5.194 to do this but even if i set the two thread pools to have one thread the app server seems to create another threads. So, i would like to know from your knowledge if this servlet is really doing non-blocking io and not blocking at any time, also it would be amazing if i could do some experiment to ensure this. I think it's important to point out that the class ServletInputStream is a subclass of InputStream, so i really don't know if this is non-blocking io. Thank you.
I have been trying to get UDP multicast working with Netty 4.0.26 and 5.0.0.Alpha2, without any success. I have adapted some code from this post which in its edited form supposedly works, but does not for me. The attached code simply echoes "Send 1", "Send 2" etc. but the corresponding packets are never received.
In the expression localSocketAddr = new InetSocketAddress(localAddr, MCAST_PORT) I have tried port 0 as well, also without success. All kinds of other combinations of bind port and local address have been tried also.
The various socket options are copied from the other post I mentioned.
Can anyone tell me what I'm doing wrong? This is with Java 8 on WIndows 8.1.
Thanks very much,
Sean
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFactory;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
public class MCast {
private static final String LOCAL_ADDR = "192.168.0.18";
private static final String MCAST_GROUP = "239.254.42.96";
private static final int MCAST_PORT = 9796;
public static void main(String[] args) throws Exception {
Thread sender = new Thread(new Sender());
Thread receiver = new Thread(new Receiver());
receiver.start();
sender.start();
sender.join();
receiver.join();
}
private static class MCastSupport {
protected InetAddress localAddr;
protected InetAddress remoteAddr;
protected InetSocketAddress localSocketAddr;
protected InetSocketAddress remoteSocketAddr;
protected DatagramChannel chan;
protected Bootstrap bootstrap;
public MCastSupport() {
try {
localAddr = InetAddress.getByName(LOCAL_ADDR);
remoteAddr = InetAddress.getByName(MCAST_GROUP);
localSocketAddr = new InetSocketAddress(localAddr, MCAST_PORT);
remoteSocketAddr = new InetSocketAddress(remoteAddr, MCAST_PORT);
NetworkInterface nif = NetworkInterface.getByInetAddress(localAddr);
bootstrap = new Bootstrap()
.group(new NioEventLoopGroup())
.handler(new SimpleChannelInboundHandler<DatagramPacket>() {
#Override
protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
System.out.println("Received: " + msg.content().getInt(0));
}
})
.channelFactory(new ChannelFactory<NioDatagramChannel>() {
#Override
public NioDatagramChannel newChannel() {
return new NioDatagramChannel(InternetProtocolFamily.IPv4);
}
})
.handler(new SimpleChannelInboundHandler<DatagramPacket>() {
#Override
protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
System.out.println("Received: " + msg.content().getInt(0));
}
})
.option(ChannelOption.SO_BROADCAST, true)
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.IP_MULTICAST_LOOP_DISABLED, false)
.option(ChannelOption.SO_RCVBUF, 2048)
.option(ChannelOption.IP_MULTICAST_TTL, 255)
.option(ChannelOption.IP_MULTICAST_IF, nif);
chan = (DatagramChannel) bootstrap.bind(localSocketAddr).sync().channel();
chan.joinGroup(remoteSocketAddr, nif).sync();
} catch (Throwable t) {
System.err.println(t);
t.printStackTrace(System.err);
}
}
}
private static class Sender extends MCastSupport implements Runnable {
#Override
public void run() {
try {
for (int seq = 1; seq <= 5; ++ seq) {
ByteBuf buf = Unpooled.copyInt(seq);
DatagramPacket dgram = new DatagramPacket(buf, remoteSocketAddr, localSocketAddr);
chan.writeAndFlush(dgram);
System.out.println("Send: " + seq);
Thread.sleep(5000);
}
} catch (Throwable t) {
System.err.println(t);
t.printStackTrace(System.err);
}
}
}
private static class Receiver extends MCastSupport implements Runnable {
#Override
public void run() {
try {
Thread.sleep(5 * 5000);
} catch (Throwable t) {
System.err.println(t);
t.printStackTrace(System.err);
}
}
}
}
The root of my issue was setting ChannelOption.IP_MULTICAST_LOOP_DISABLED to false. Leaving out that line (i.e. allowing IP_MULTICAST_LOOP_DISABLED to default to true) allows multicast to work as expected. Frankly, this doesn't make a lot of sense to me, but I have no more time to investigate.
I'm developing a JAVA program that prints a file.
I need to know when the printer has completed printing the file, I've found this simple code that it is interesting:
import javax.print.*;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.PrintServiceAttributeSet;
import javax.print.attribute.standard.PrinterStateReason;
import javax.print.attribute.standard.PrinterStateReasons;
import javax.print.attribute.standard.Severity;
import javax.print.event.*;
import java.awt.*;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.*;
import java.util.Set;
/**
* PrintTest
*/
public class PrintTest implements PrintServiceAttributeListener,PrintJobListener,Doc, Printable, PrintJobAttributeListener {
private static final transient String TEXT = "12345";
public static void main(String[] args) {
PrintTest test = new PrintTest();
test.checkPrinters();
}
public void checkPrinters() {
Thread newThread = new Thread(new Runnable() {
public void run() {
PrintService ps = PrinterJob.getPrinterJob().getPrintService();
DocFlavor[] myFlavors = ps.getSupportedDocFlavors();
ps.addPrintServiceAttributeListener(PrintTest.this);
DocPrintJob docJob = ps.createPrintJob();
docJob.addPrintJobAttributeListener(PrintTest.this, null);
docJob.addPrintJobListener(PrintTest.this);
try {
docJob.print(PrintTest.this,null);
}
catch (PrintException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
} });
newThread.start();
/**
PrintServiceAttributeSet attSet = ps.getAttributes();
PrinterStateReasons psr = ps.getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
} */
}
public void attributeUpdate(PrintServiceAttributeEvent psae) {
System.out.println(psae.getAttributes());
}
public void printDataTransferCompleted(PrintJobEvent pje) {
System.out.println("Transfer completed");
}
public void printJobCompleted(PrintJobEvent pje) {
System.out.println("Completed");
}
public void printJobFailed(PrintJobEvent pje) {
System.out.println("Failed");
PrinterStateReasons psr = pje.getPrintJob().getPrintService().getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
}
}
public void printJobCanceled(PrintJobEvent pje) {
System.out.println("Canceled");
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
System.out.println("No more events");
}
public void printJobRequiresAttention(PrintJobEvent pje) {
System.out.println("Job requires attention");
PrinterStateReasons psr = pje.getPrintJob().getPrintService().getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
}
}
public DocFlavor getDocFlavor() {
return DocFlavor.SERVICE_FORMATTED.PRINTABLE; //To change body of implemented methods use File | Settings | File Templates.
}
public Object getPrintData() throws IOException {
return this;
}
public DocAttributeSet getAttributes() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Reader getReaderForText() throws IOException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public InputStream getStreamForBytes() throws IOException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
return pageIndex == 0 ? PAGE_EXISTS : NO_SUCH_PAGE; //To change body of implemented methods use File | Settings | File Templates.
}
public void attributeUpdate(PrintJobAttributeEvent pjae) {
System.out.println("Look out");
}
}
So, the method that interest me is this:
public void printJobCompleted(PrintJobEvent pje) {
System.out.println("Completed");
}
but it doesn't works for me. The issue is that the printer doesn't support this type of code. Can someone tell me a model of printer that support this code?
Look at the sample code here:
It looks like you need to implement your PrintJobAdapter. The relevant bits are:
package com.your.package;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.event.PrintJobAdapter;
import javax.print.event.PrintJobEvent;
public class DetermineThatPrintJobHasFinished {
public static void main(String[] args) throws Exception {
//... see example in link
// Locate the default print service for this environment.
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
// Create and return a PrintJob capable of handling data from
// any of the supported document flavors.
DocPrintJob printJob = service.createPrintJob();
// register a listener to get notified when the job is complete
JobCompleteMonitor monitor = new JobCompleteMonitor();
printJob.addPrintJobListener(monitor);
// Construct a SimpleDoc with the specified print data, doc flavor and doc attribute set.
Doc doc = new SimpleDoc(is, flavor, null);
// Print a document with the specified job attributes.
printJob.print(doc, null);
monitor.waitForJobCompletion();
is.close();
}
private static class JobCompleteMonitor extends PrintJobAdapter {
private boolean completed = false;
#Override
public void printJobCanceled(PrintJobEvent pje) {
signalCompletion();
}
#Override
public void printJobCompleted(PrintJobEvent pje) {
signalCompletion();
}
#Override
public void printJobFailed(PrintJobEvent pje) {
signalCompletion();
}
#Override
public void printJobNoMoreEvents(PrintJobEvent pje) {
signalCompletion();
}
private void signalCompletion() {
synchronized (JobCompleteMonitor.this) {
completed = true;
JobCompleteMonitor.this.notify();
}
}
public synchronized void waitForJobCompletion() {
try {
while (!completed) {
wait();
}
} catch (InterruptedException e) {
}
}
}
}
it's not the best efficient but you could wait until the Attribute: 'queued-job-count' is equal to Zero :
public final static void waitEndJobs(final PrintService printService) throws InterruptedException {
int queue = 1;
while (queue != 0) {
final AttributeSet attributes = printService.getAttributes();
final Attribute a = Arrays.stream(attributes.toArray())//
.filter(o -> o.getName().equalsIgnoreCase("queued-job-count"))//
.findFirst()//
.orElse(null);
queue = Integer.parseInt(attributes.get(a.getClass()).toString());
Thread.sleep(5000);
}
}
To my point Rx or Project Reactor can very help with this old java printer api. I also have faced this problem recently, and currently I have finished on next version. maybe it will help to somebody
first, if you are using pdfbox as me, then
#Slf4j
#Service
#RequiredArgsConstructor
public class PrinterDeviceServiceImpl implements PrinterDeviceService {
#Override
public StreamEx<PrintService> getAvailablePrinters() {
return of(PrintServiceLookup.lookupPrintServices(null, null));
}
#Override
public boolean isPrinterExists(String printerName) {
return getAvailablePrinters()
.anyMatch(p -> p.getName().equals(printerName));
}
#Override
public PrintService getPrinter(String printerName) {
return getAvailablePrinters()
.findFirst(p -> p.getName().equals(printerName))
.orElse(null);
}
#Override
public Mono<PrintTaskStatus> print(String printerName, InputStream source) {
try {
PrintService printer = getPrinter(printerName);
if (printer == null) {
return Mono.error(new RuntimeException("printer is null"));
}
PDDocument document = Unchecked.supplier(() -> PDDocument.load(source));
PrinterJob job = PrinterJob.getPrinterJob();
job.setPageable(new PDFPageable(document, Orientation.PORTRAIT));
job.setPrintService(printer);
Paper paper = new Paper();
paper.setSize(500, 500); //TODO: lets get it from configs or task request
paper.setImageableArea(0.0, 0.0, paper.getWidth(), paper.getHeight()); // no margins
// custom page format
PageFormat pageFormat = new PageFormat();
pageFormat.setPaper(paper);
Book book = new Book();
book.append(new PDFPrintable(document), pageFormat, document.getNumberOfPages());
job.setPageable(book);
HashPrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
attr.add(OrientationRequested.PORTRAIT);
attr.add(PrintQuality.HIGH);
job.print(attr);
return Mono.create(sink -> {
/*If exec thread is UI or from http pool, then maybe better idea is to attach it to another independent one or run print in another one!*/
while (!isPrintCompleted(printer)) {
log.debug("I'm waiting to printer processed queue");
Unchecked.runnable(() -> Thread.sleep(1000));
}
/*you can wait some fixed or dynamic time based on how big your document etc and finish with error state if it needed*/
log.debug("printer queue have processed :)");
sink.success(PrintTaskStatus.Completed);
});
} catch (Throwable ex) {
ExceptionHelpers.logError(ex, log);
return Mono.just(PrintTaskStatus.Failed);
}
}
private boolean isPrintCompleted(PrintService printer) {
return Arrays.stream(printer.getAttributes().toArray())
.filter(att -> att instanceof QueuedJobCount)
.map(QueuedJobCount.class::cast)
.findFirst()
.map(queuedJobCount -> queuedJobCount.getValue() == 0)
.orElse(false);
}
}
second, if you are preferred only default printer api then replace print method to:
#Override
public Mono<PrintTaskStatus> print(String printerName, InputStream source) {
PrintService printer = getPrinter(printerName);
if (printer == null) {
return Mono.error(new RuntimeException("printer is null"));
}
try {
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
DocPrintJob printJob = printer.createPrintJob();
CustomPrintJobListener monitor = new CustomPrintJobListener();
printJob.addPrintJobListener(monitor);
Doc doc = new SimpleDoc(source, flavor, null);
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(OrientationRequested.PORTRAIT);
pras.add(PrintQuality.NORMAL);
pras.add(new Copies(1));
printJob.print(doc, pras);
return monitor.getJobMono();
} catch (Exception ex) {
ExceptionHelpers.logError(ex, log);
return Mono.just(PrintTaskStatus.Failed);
}
}
#Slf4j
private static class CustomPrintJobListener extends PrintJobAdapter {
private final EmitterProcessor<PrintTaskStatus> emitter = EmitterProcessor.create();
#Override
public void printJobCanceled(PrintJobEvent pje) {
emitter.onNext(PrintTaskStatus.Canceled);
log.info("Print job canceled :| ");
}
#Override
public void printDataTransferCompleted(PrintJobEvent pje) {
log.info("Print data transfer completed ;) ");
}
#Override
public void printJobCompleted(PrintJobEvent pje) {
emitter.onNext(PrintTaskStatus.Completed);
log.info("Print job completed :) ");
}
#Override
public void printJobFailed(PrintJobEvent pje) {
emitter.onNext(PrintTaskStatus.Failed);
log.info("Print job failed :( ");
}
#Override
public void printJobNoMoreEvents(PrintJobEvent pje) {
emitter.onNext(PrintTaskStatus.Completed);
log.info("No more events to the job :|");
}
#Override
public void printJobRequiresAttention(PrintJobEvent pje) {
log.info("Print job requires attention :O ");
}
public Mono<PrintTaskStatus> getJobMono() {
return emitter.next();
}
}
Good luck :)
I'm running a simple client/server XML-RPC app to understand better the Apache XMLRPC library.
But I would like to be able to print or debug the XML output that the client sends and the XML received at server. How could I find these data??
//StartServer.java
public class StartServer {
public static void main(String args[]) throws Exception {
Server server = new Server();
}
}
//Server.java
import org.apache.xmlrpc.server.PropertyHandlerMapping;
import org.apache.xmlrpc.server.XmlRpcServer;
import org.apache.xmlrpc.server.XmlRpcServerConfigImpl;
import org.apache.xmlrpc.webserver.WebServer;
public class Server {
private static final int port = 3000;
public Server() throws Exception {
WebServer webServer = new WebServer(port);
XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();
PropertyHandlerMapping phm = new PropertyHandlerMapping();
phm.addHandler("reply", ReplyClass.class);
xmlRpcServer.setHandlerMapping(phm);
XmlRpcServerConfigImpl serverConfig =
(XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
serverConfig.setEnabledForExtensions(true);
serverConfig.setContentLengthOptional(false);
webServer.start();
}
}
//ReplyClass.java
public class ReplyClass {
public int reply(Object params[]){
for(int i = 0; i< params.length; i++){
System.out.println( "Params :"+params[i].toString());
}
return 0;
}
public int foo(int x){
System.out.println("foo : "+ x);
return 1;
}
}
//XMLRPCtest
import java.net.URL;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.client.XmlRpcLocalTransportFactory;
import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory;
public class XMLRPCtest {
private XmlRpcClient client;
public XMLRPCtest() {
try {
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("http://localhost:3000"));
config.setEnabledForExtensions(true);
client = new XmlRpcClient();
client.setConfig(config);
} catch (Exception exception) {
exception.printStackTrace();
}
}
public Object execute(String command, Object[] params) {
try {
Object reply = client.execute(command, params);
return reply;
} catch (XmlRpcException e) {
e.printStackTrace();
return null;
}
}
public static void main(String args[]) {
try {
XMLRPCtest client = new XMLRPCtest();
int data[] = {};
Object[] params = new Object[]{1};
Integer result = (Integer) client.execute("reply.foo", params);
System.out.println("Result: " + result);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}