I am working with JADE ( Java Agent Development framework), and I am trying to write a behavior which makes an agent moving from container to another. I tried this command:
public void action() {
ACLMessage msg = myAgent.receive(template);
if (msg != null) {
moveRequest = msg;
String destination =
doMove(new ContainerID(destination, null));
}
else {
block();
}
}
but it seems that I have a failure in moving:
jade.core.mobility.AgentMobilityService$CommandSourceSink handleInformMoved Grave: Mobility protocol not supported. Aborting transfer
It will be better if I get the source code for a complete behavior.
Thanks in advance
this is the code to start the jade platform:
import jade.core.Profile;
import jade.core.ProfileImpl;
import jade.core.Runtime;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
public class Run {
public Run() {
Runtime rt = Runtime.instance();
rt.setCloseVM(true);
AgentContainer mc = rt.createMainContainer(new ProfileImpl());
Profile p = new ProfileImpl();
p.setParameter("container-name", "Foo");
AgentContainer ac = rt.createAgentContainer(p);
try{
AgentController rma = mc.createNewAgent("rma", "jade.tools.rma.rma", null);
rma.start();
AgentController ma = mc.createNewAgent("MA", "MobileAgent", null);
ma.start();
}
catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
new Run();
}
}
And this is the code for the mobile agent. After being created, the agent moves immediately to the container Foo.
import jade.core.Agent;
import jade.core.Location;
public class MobileAgent extends Agent {
private static final long serialVersionUID = 1L;
#Override
protected void setup() {
System.out.println("Hello World");
Location destination = new jade.core.ContainerID("Foo", null);
doMove(destination);
super.setup();
}
#Override
protected void beforeMove() {
System.out.println("Preparing to move");
super.beforeMove();
}
#Override
protected void afterMove() {
System.out.println("Arrived to destination");
super.afterMove();
}
}
Related
So basically I have a MainConstroller class that has methods for every button. I have also a server multi-client application. In Client I have a method sendMessage that sends a String and an Object as a parameter to outputStreams to Server.
In the same method I have 2 inputStream for message from server and an object. The problem is that this method runs on a Thread which implements run method and I cannot return the object.
I tried to create a static class that saves these, but the getters are null, when called in Controller class.
What is the best method to achieve this?
public void onSaveButton(javafx.event.ActionEvent actionEvent) throws Exception {
Parent root = null;
Boolean type = false;
String message = null;
if (adminCheckbox.isSelected()) {
root = FXMLLoader.load(getClass().getResource("/fxml/admin.fxml"));
type = true;
message = "Admin";
}
if (competitorCheckbox.isSelected()) {
root = FXMLLoader.load(getClass().getResource("/fxml/competitor.fxml"));
message = "Competitor";
}
PersonEntity personEntity = new PersonEntity();
personEntity.setIdTeam(Integer.parseInt(teamField.getText()));
personEntity.setType(type);
personEntity.setUsername(usernameField.getText());
client.sendMessageToServer(message, personEntity);
System.out.println(Utils.getMessage());}
And the Client method:
public void sendMessageToServer(String message, Object object) throws Exception {
new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Say something and the message will be sent to the server: ");
//For receiving and sending data
boolean isClose = false;
while (!isClose) {
try {
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
if (message.equals("Bye")) {
isClose = true;
}
outputStream.writeObject(message);
outputStream.writeObject(object);
String messageFromServer = (String) inputStream.readObject();
//System.out.println(messageFromServer);
int index = messageFromServer.indexOf(' ');
String word = messageFromServer.substring(0, index);
if (messageFromServer.equals("Bye")) {
isClose = true;
}
if (!word.equals("LIST")) {
Object obj = (Object) inputStream.readObject();
Utils.setMessage(messageFromServer);
return;
//Utils.setObject(obj);
//System.out.println("IN FOR " + Utils.getMessage());
} else {
List<Object> list = (List<Object>) inputStream.readObject();
Utils.setMessage(messageFromServer);
Utils.setObjects(list);
return;
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
I don't know what your server is, nor the rest of your app. I know you are using raw TCP sockets for communication using a custom protocol.
What I did was take code for a similar example from the Java tutorials. The code is the KnockKnock client server code from: Writing the Server Side of a Socket. The basic server code is unchanged, I just replaced the console-based client with a JavaFX UI.
Unchanged server code:
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KnockKnockProtocol.java
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KKMultiServer.java
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KKMultiServerThread.java
Replaced console client:
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KnockKnockClient.java
I provide two different client implementations; one makes synchronous client calls on the JavaFX application thread, the other makes asynchronous client calls using a JavaFX task.
The current asynchronous task-based solution is not robust enough for a full-scale production system as it is technically possible for it to lose messages and it doesn't robustly match request and response messages. But for a demo like this it is OK.
For simple execution, the UI apps both launch a local server on a pre-defined port when they are run, but you could remove the code to launch the server from the UI apps and run the server from the command line if you want.
KnockKnockSyncClient.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class KnockKnockSyncClient {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
public String connect(String host, int port) {
try {
socket = new Socket(host, port);
out = new PrintWriter(
socket.getOutputStream(),
true
);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()
)
);
return in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String sendMessage(String request) {
String response = null;
try {
out.println(request);
response = in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
public void disconnect() {
try {
if (socket != null) {
socket.close();
socket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
KnockKnockSyncApp
import javafx.animation.FadeTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class KnockKnockSyncApp extends Application {
private static final String HOST = "localhost";
private static final int PORT = 8809;
public static final String QUIT_RESPONSE = "Bye.";
private ExecutorService serverExecutor;
private KnockKnockSyncClient client;
private static final String CSS = """
data:text/css,
.root {
-fx-font-size: 20;
}
.list-cell {
-fx-alignment: baseline-right;
-fx-text-fill: purple;
}
.list-cell:odd {
-fx-alignment: baseline-left;
-fx-text-fill: darkgreen;
}
""";
#Override
public void init() {
serverExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "KKServer"));
serverExecutor.submit(
() -> {
try {
KKMultiServer.main(new String[]{ PORT + "" });
} catch (Exception e) {
e.printStackTrace();
}
}
);
client = new KnockKnockSyncClient();
}
#Override
public void start(Stage stage) {
ListView<String> messageView = new ListView<>();
TextField inputField = new TextField();
inputField.setPromptText("Enter a message for the server.");
inputField.setOnAction(event -> {
String request = inputField.getText();
messageView.getItems().add(request);
String response = client.sendMessage(request);
messageView.getItems().add(response);
messageView.scrollTo(Math.max(0, messageView.getItems().size() - 1));
inputField.clear();
if (QUIT_RESPONSE.equals(response)) {
closeApp(inputField.getScene());
}
});
VBox layout = new VBox(10,
messageView,
inputField
);
layout.setPadding(new Insets(10));
layout.setPrefWidth(600);
Scene scene = new Scene(layout);
scene.getStylesheets().add(CSS);
stage.setScene(scene);
stage.show();
inputField.requestFocus();
String connectResponse = client.connect(HOST, PORT);
if (connectResponse != null) {
messageView.getItems().add(connectResponse);
}
}
private void closeApp(Scene scene) {
Parent root = scene.getRoot();
root.setDisable(true);
FadeTransition fade = new FadeTransition(Duration.seconds(1), root);
fade.setToValue(0);
fade.setOnFinished(e -> Platform.exit());
fade.play();
}
#Override
public void stop() {
client.disconnect();
serverExecutor.shutdown();
}
public static void main(String[] args) {
launch();
}
}
KnockKnockAsyncClient.java
import javafx.concurrent.Task;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class KnockKnockAsyncClient extends Task<Void> {
private final String host;
private final int port;
private final BlockingQueue<String> messageQueue = new LinkedBlockingDeque<>();
public KnockKnockAsyncClient(String host, int port) {
this.host = host;
this.port = port;
}
#Override
protected Void call() {
try (
Socket kkSocket = new Socket(host, port);
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(kkSocket.getInputStream()));
) {
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
// this is not a completely robust implementation because updateMessage
// can coalesce responses and there is no matching in send message calls
// to responses. A more robust implementation may allow matching of
// requests and responses, perhaps via a message id. It could also
// replace the updateMessage call with storage of results in a collection
// (e.g. an observable list) with thread safe notifications of response
// arrivals, e.g. through CompleteableFutures and/or Platform.runLater calls.
updateMessage(fromServer);
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break;
fromUser = messageQueue.take();
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
} catch (InterruptedException e) {
if (isCancelled()) {
updateMessage("Cancelled");
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void sendMessage(String request) {
messageQueue.add(request);
}
}
KnockKnockAsyncApp.java
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class KnockKnockAsyncApp extends Application {
private static final String HOST = "localhost";
private static final int PORT = 8809;
public static final String QUIT_RESPONSE = "Bye.";
private ExecutorService serverExecutor;
private ExecutorService clientExecutor;
private static final String CSS = """
data:text/css,
.root {
-fx-font-size: 20;
}
.list-cell {
-fx-alignment: baseline-right;
-fx-text-fill: purple;
}
.list-cell:odd {
-fx-alignment: baseline-left;
-fx-text-fill: darkgreen;
}
""";
#Override
public void init() {
serverExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "KKServer"));
serverExecutor.submit(
() -> {
try {
KKMultiServer.main(new String[]{ PORT + "" });
} catch (Exception e) {
e.printStackTrace();
}
}
);
clientExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
final AtomicInteger threadNum = new AtomicInteger(0);
#Override
public Thread newThread(Runnable r) {
return new Thread(r,"KKClient-" + threadNum.getAndAdd(1));
}
});
}
#Override
public void start(Stage stage) {
ListView<String> messageView = new ListView<>();
KnockKnockAsyncClient client = new KnockKnockAsyncClient(HOST, PORT);
// monitor and action responses from the server.
client.messageProperty().addListener((observable, oldValue, response) -> {
if (response != null) {
logMessage(messageView, response);
}
if (QUIT_RESPONSE.equals(response)) {
closeApp(messageView.getScene());
}
});
TextField inputField = new TextField();
inputField.setPromptText("Enter a message for the server.");
inputField.setOnAction(event -> {
String request = inputField.getText();
logMessage(messageView, request);
client.sendMessage(request);
inputField.clear();
});
VBox layout = new VBox(10,
messageView,
inputField
);
layout.setPadding(new Insets(10));
layout.setPrefWidth(600);
Scene scene = new Scene(layout);
scene.getStylesheets().add(CSS);
stage.setScene(scene);
stage.show();
inputField.requestFocus();
clientExecutor.submit(client);
}
private void logMessage(ListView<String> messageView, String request) {
messageView.getItems().add(request);
messageView.scrollTo(Math.max(0, messageView.getItems().size() - 1));
}
private void closeApp(Scene scene) {
Parent root = scene.getRoot();
root.setDisable(true);
FadeTransition fade = new FadeTransition(Duration.seconds(1), root);
fade.setToValue(0);
fade.setOnFinished(e -> Platform.exit());
fade.play();
}
#Override
public void stop() {
clientExecutor.shutdown();
serverExecutor.shutdown();
}
public static void main(String[] args) {
launch();
}
}
You can use a thread-safe ConcurrentLinkedQueue (static, of course). Utils.setObjects would add each element to the queue. On the UI thread, you would occasionally poll for new items on the queue to be displayed in the UI.
Reference documentation: https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html
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 am working on a socket server for a MMORPG I am creating, and I am unsure how to organize commands and handlers for readability.
I will be getting the command from data[0], such as ban, kick, identify, etc. I have read that you can use a HashMap and have an Interface Command, and create a new class for each handler/command that implements Command. You'd then create a HashMap and go from there. I have also read that you can reflection. I want to do what an experienced programmer would do.
Client Class:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client implements Runnable {
private Socket socket;
private Server server;
private boolean isConnected;
private BufferedReader in;
private PrintWriter out;
public Client(Socket socket, Server server) {
this.socket = socket;
this.server = server;
this.isConnected = true;
this.in = null;
this.out = null;
}
#Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (isConnected) {
String recv = in.readLine().trim();
if (recv != null) {
String[] data = recv.split("%");
}
}
} catch (IOException e) {}
}
public synchronized void send(String data) {
out.println(data);
}
}
What you want is to use the Command Pattern.
Here is how I would use the Command Pattern for handling commands from a client.
/* Command Exception. */
public class ClientCommandException extends Exception {
public ClientCommandException(String msg) {
super(msg);
}
}
/* The ClientCommand interface */
public interface ClientCommand {
void execute(Client client, String[] params) throws ClientCommandException;
}
import java.util.HashMap;
import java.util.Arrays;
/* Container for commands */
public class Commands implements ClientCommand {
private HashMap<String, ClientCommand> cmds;
public Commands() {
cmds = new HashMap<String, ClientCommand>();
}
public void addCommand(ClientCommand cmd, String name) {
cmds.put(name, cmd);
}
public void execute(Client client, String[] params) throws ClientCommandException {
ClientCommand cmd = cmds.get(params[0]);
if(cmd != null) {
cmd.execute(client, Arrays.copyOfRange(params, 1, params.length));
} else {
throw new ClientCommandException("Unknown Command: " + params[0]);
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class Client implements Runnable {
private boolean isConnected;
private Commands cmds;
private BufferedReader in;
private PrintWriter out;
private class EchoCommand implements ClientCommand {
public void execute(Client client, String[] params) throws ClientCommandException {
StringBuilder b = new StringBuilder("Echo back:");
int len = params.length;
for(int i = 0; i < len; i++) {
b.append(' ');
b.append(params[i]);
}
client.send(b.toString());
}
}
private class DisconnectCommand implements ClientCommand {
public void execute(Client client, String[] params) throws ClientCommandException {
client.close();
}
}
public Client() {
cmds = new Commands();
cmds.addCommand(new EchoCommand(), "echo");
cmds.addCommand(new DisconnectCommand(), "disconnect");
/* sub-commands */
Commands server = new Commands();
server.addCommand(new EchoCommand(), "print");
cmds.addCommand(server, "server");
isConnected = true;
}
public void addCommand(ClientCommand cmd, String name) {
cmds.addCommand(cmd, name);
}
public void close() {
isConnected = false;
}
#Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(System.in));
out = new PrintWriter(System.out, true);
while (isConnected) {
String recv = in.readLine().trim();
if (recv != null) {
String[] data = recv.split("%");
try {
cmds.execute(this, data);
} catch(ClientCommandException e) {
/* Return some error back to the client. */
out.println(e.toString());
}
}
}
} catch (IOException e) {}
}
public synchronized void send(String data) {
out.println(data);
}
public static void main(String[] args){
Client client = new Client();
System.out.println("Start Client.");
client.run();
}
}
I'm currently playing with the Java SASL API and I wrote a little program to simulate a challenge response sequence using CRAM-MD5. However, I'm unsure about how to do this, as SaslClient and SaslServer only have methods evaluateChallenge(...) and evaluateResponse(...). I would expect SaslServer to have a method like issueChallenge(...) or something like that, but it has not. So what is the correct way to do this?
Below you find my (not working) code.
package mypackage;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
public class Main {
public static void main(String[] args) throws SaslException {
new Main().start();
}
private static class ClientHandler implements CallbackHandler {
#Override
public void handle(Callback[] cbs) throws IOException, UnsupportedCallbackException {
for (Callback cb : cbs) {
if (cb instanceof NameCallback) {
System.out.println("Client - NameCallback");
NameCallback nc = (NameCallback)cb;
nc.setName("username");
} else if (cb instanceof PasswordCallback) {
System.out.println("Client - PasswordCallback");
PasswordCallback pc = (PasswordCallback)cb;
pc.setPassword("password".toCharArray());
}
}
}
}
private static class ServerHandler implements CallbackHandler {
#Override
public void handle(Callback[] cbs) throws IOException, UnsupportedCallbackException {
for (Callback cb : cbs) {
if (cb instanceof AuthorizeCallback) {
System.out.println("Server - AuthorizeCallback");
AuthorizeCallback ac = (AuthorizeCallback)cb;
ac.setAuthorized(true);
} else if (cb instanceof NameCallback) {
System.out.println("Server - NameCallback");
NameCallback nc = (NameCallback)cb;
nc.setName("username");
} else if (cb instanceof PasswordCallback) {
System.out.println("Server - PasswordCallback");
PasswordCallback pc = (PasswordCallback)cb;
pc.setPassword("password".toCharArray());
}
}
}
}
private void start() throws SaslException {
byte[] challenge;
byte[] response;
ClientHandler clientHandler = new ClientHandler();
ServerHandler serverHandler = new ServerHandler();
SaslClient sc = Sasl.createSaslClient(new String[] { "CRAM-MD5" }, null, "my_server", "FQHN", null, clientHandler);
SaslServer ss = Sasl.createSaslServer("CRAM-MD5", "my_server", "FQHN", null, serverHandler);
// Challenge response sequence (not working)
challenge = ss.evaluateResponse(null);
response = sc.evaluateChallenge(challenge);
ss.evaluateResponse(response);
if (ss.isComplete()) {
System.out.println("Authentication successful.");
}
}
}
Greetings, Fred
I was able to get the above code working by changing one line
from
challenge = ss.evaluateResponse(null);
to
challenge = ss.evaluateResponse(new byte[0]);
The javadoc for evaluateResponse() says
this method is called to prepare an appropriate next challenge to submit to the client
So I guess from the above, there is no need for a issueChallange() method, evaluateResponse() takes care of issuing the response.