JavaFX FadeTransition end other SetVisbilities stop working when I call a new method - sockets

I want to make a FadeTransition within a pane in my application. Also, with this FadeTransition I set the visibitilitys of some JavaFX inside the pane to false, to make them disappear. It's working fine but, when I call another method that I named waitForResponse(event) after the FadeTransition it just stops working. I don't know why.
If I comment the waitForResponse(event) the FadeTransitions start working again.
I've thought that maybe it's a problem with the Socket and the InputStreamReader inside the waitForResponse(event), but I tested taking it out and making another basic thing inside this method still not work.
I've made other tests and dicovered that FadeTransition and other visibility changes doesn't work if I put any bufferedReader, other loops ou decision structures after it.
I just want to make a loading screen that prevent user to click anywhere until it's finished.
This is the code:
public class LoadingScreenController implements Initializable {
// Socket que vai ser utilizado nos vários métodos para conversar com o servidor
private Socket cliente;
// PrintWriter que vai ser utilizado pelos vários métodos e vai passar o
// argumento para o switch case
private PrintWriter pr;
private InputStreamReader in;
private BufferedReader bf;
private String option;
private String response;
#FXML
private Button refreshButton;
#FXML
private ImageView loadingGif;
#FXML
private Label txtLabel;
#FXML
private AnchorPane rootPane;
public String getOption() {
return option;
}
public void setOption(String option) {
this.option = option;
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
private void makeFadeInTransition() {
FadeTransition fadeTransition = new FadeTransition(Duration.seconds(1), loadingGif);
fadeTransition.setFromValue(0.0);
fadeTransition.setToValue(1.0);
fadeTransition.play();
}
#FXML
private void onRefreshButtonAction(ActionEvent event) {
if (option == null) {
throw new IllegalStateException("Entity was null");
}
refreshButton.setVisible(false);
refreshButton.setDisable(true);
txtLabel.setVisible(false);
makeFadeInTransition();
sendOptionToServer(event);
}
#FXML
private void sendOptionToServer(ActionEvent event) {
try {
cliente = new Socket("localhost", 3322);
pr = new PrintWriter(cliente.getOutputStream());
in = new InputStreamReader(cliente.getInputStream());
bf = new BufferedReader(in);
pr.println(option);
pr.flush();
waitForReponse(event, bf);
} catch (IOException e) {
e.printStackTrace();
}
}
private void waitForReponse(ActionEvent event, BufferedReader bf) throws IOException {
response = bf.readLine();
switch (response) {
case "a":
Utils.currentStage(event).close();
break;
}
}
}

Your sendOptionToServer(...) method, and in particular your waitForResponse(...) method, contains blocking calls that block execution until they are complete (i.e. until you receive a response from the server). Since you're running these on the FX Application Thread, you prevent that thread from doing its normal work until those calls complete. This means it won't update the UI or process any user events until you have received and processed the response from the server.
You should place the calls to blocking methods in a background thread to allow the FX Application Thread to proceed in the meantime. The javafx.concurrent API makes this reasonably easy to do; here a Task should suffice.
Here's a version that uses a Task. I also used a "try with resources" to ensure everything that needs to be closed is correctly closed.
#FXML
private void sendOptionToServer(ActionEvent event) {
Task<String> serverCommunicationTask = new Task<>() {
#Override
protected String call() throws Exception {
try (
Socket cliente = new Socket("localhost", 3322);
PrintWriter pr = new PrintWriter(cliente.getOutputStream());
BufferedReader bf = new BufferedReader(new InputStreamReader(cliente.getInputStream()));
) {
pr.println(option);
pr.flush();
return bf.readLine();
}
}
};
serverCommunicationTask.setOnSucceeded(event -> {
if ("a".equals(serverCommunicationTask.getValue())) {
rootPane.getScene().getWindow().hide();
}
});
serverCommunicationTask.setOnFailed(event -> {
event.getException().printStackTrace();
// handle exception...
});
Thread thread = new Thread(serverCommunicationTask);
thread.setDaemon(true);
thread.start();
}

Related

Asynchronous GET on REST with okhttp3

I am trying to perform an asynchronous GET-request on my openHAB-project. I have done it before and reused parts of my code to create a new Android app, but it is not working.
In theory I want the state of the "GastSwitch"-item to be written into a String (gastSwitchState) to then be used as a trigger for opening a different activity. If the result of the request is "OFF" the app is supposed to keep running, but stay in the MainActivity.
When debugging it seems like the getGastSwitchState-method is jumped entirely after the enqeue-Method is called. Can someone explain to me, why my code seems to leave out half of the method?
I know that this way of doing it should work, but I can't find where I went wrong.
//connect with REST-API in openHAB :
// GET Status GastSwitch: if Switch = "ON" go to MeetingActivity
//Timer to GET the GastSwitch-status every 30 seconds:
TimerTask gastSwitchTimerTask = new TimerTask() {
public void run() {
try {
getGastSwitchState("myURLforOpenHABGastSwitchState", new Callback() {
#Override
public void getParameter(String string) {
if (gastSwitch.equals("ON")) {
Intent activityIntent = new Intent(getApplicationContext(), MeetingActivity.class);
startActivity(activityIntent);
}
}
});
} catch (IOException e) {
e.printStackTrace();
tvLog.setText(e.toString());
}
}
};
// Timer for GETting the GastSwitch-state every 30 seconds
long emergencyDelay = 1000 * 30 * 1;
Timer gastSwitchTimer = new Timer();
gastSwitchTimer.schedule(gastSwitchTimerTask, 0, emergencyDelay);
}
//Method for GETting the GastSwitch-state from REST-API:
void getGastSwitchState(String url, final Callback callback) throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
okhttp3.Request request = new okhttp3.Request.Builder()
.url(url)
.method("GET", null)
.addHeader("AuthToken", "")
.build();
client.newCall(request)
.enqueue(new okhttp3.Callback() {
#Override
public void onResponse(#NotNull okhttp3.Call call, #NotNull Response response) throws IOException {
if (response.isSuccessful()) {
final String res = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
gastSwitch = res;
tvLog.setText(gastSwitch);
callback.getParameter(gastSwitch);
}
});
}
}
#Override
public void onFailure(#NotNull okhttp3.Call call, #NotNull IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
});

Netty client generates lots of TIME_WAIT socket states

I have written a netty client code to send some processed data to multiple clients. After running for 3-4 hours I exhaust all sockets and no more connections possible. Also when I check the socket states in the OS a large number of sockets are in TIME_WAIT state.
public class NettyClient {
private static LogHelper logger = new LogHelper(NettyClient.class);
private static EventLoopGroup workerGroup = new NioEventLoopGroup();
private static Bootstrap nettyClient = new Bootstrap()
.group(workerGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);
private URL url;
private RequestVo Req;
private ChannelFuture chFuture;
private Object ReportData;
private JAXBContext jbContext;
private static final int CHANNEL_READ_TIMEOUT = 5;
public NettyClient() {
// TODO Auto-generated constructor stub
}
public NettyClient(RequestVo Req, JAXBContext jbCtx,Object data) {
this.Req = Req;
this.ReportData = data;
this.jbContext = jbCtx;
}
public void sendRequest() {
logger.debug("In sendRequest()");
//ChannelFuture chFuture = null;
try {
this.url = new URL(Req.getPushAddress());
//add handlers
nettyClient.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast("timeout",
new ReadTimeoutHandler(CHANNEL_READ_TIMEOUT, TimeUnit.SECONDS));
ch.pipeline()
.addLast("codec", new HttpClientCodec());
ch.pipeline()
.addLast("inbound",
new NettyClientInBoundHandler(Req, jbContext, ReportData));
}
});
//make a connection to the Client
int port = url.getPort() == -1? url.getDefaultPort():url.getPort();
chFuture = nettyClient.connect(url.getHost(), port);
chFuture.addListener(new NettyClientConnectionListener(this.Req.getRequestId()));
} catch (Exception e) {
logger.error("Exception: Failed to connect to Client ", e);
} finally {
}
}
}
Here are the methods from ChannelInBoundHandler Class
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
Map<String, String> props = new HashMap<String, String>();
if(msg instanceof HttpResponse) {
logger.debug("channelRead()");
HttpResponse httpRes = (HttpResponse) msg;
HttpResponseStatus httpStatus = httpRes.status();
props.put(REQUEST_ID, this.Request.getRequestId());
props.put(CLIENT_RESPONSE_CODE, String.valueOf(httpStatus.code()));
JmsService.getInstance(DESTINATION).sendTextMessage(props, "");
logger.debug("channelRead() HttpResponse Code: " + httpStatus.code());
ctx.close();
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
Map<String, String> props = new HashMap<String, String>();
logger.error("exceptionCaught()", cause);
if(cause instanceof ReadTimeoutException) {
//If read-timeout, send back the response
props.put(REQUEST_ID, this.Request.getRequestId());
props.put(CLIENT_RESPONSE_CODE,
String.valueOf(HttpResponseStatus.REQUEST_TIMEOUT.code()));
JmsService.getInstance(DESTINATION).sendTextMessage(props, "");
ctx.close();
}
else {
logger.error("Exception: ", cause);
}
}
Any idea what is wrong in the code would greatly help me.
Thanks
I'm not familiar with netty, but I think I can explain part of your problem, and hopefully help you along the way:
When you make use of a port and then close it, the port will not automatically be available for use by other processes at once. Instead, it will go into the TIME_WAIT state for a certain period of time. For Windows, I believe this will be 240 seconds (four minutes).
I'd guess that your code is slowly using up all the available ports on your system, due to the release of ports from the TIME_WAIT state is happening too slowly.
It's not entirely clear to me where the actual port numbers are coming from (are they auto-generated by url.getDefaultPort() perhaps?), but perhaps you can find some way to reuse them? If you can keep one or more open connections and somehow reuse these, then you might be able to decrease the frequency of requests for new ports enough for the closed ports to go out of their TIME_WAIT state.

Issue with UploadServlet in GWT Project - empty MultiPart

I'm developing a web-app using GWT, and I need to upload a file to the server.
I've written this servlet (which I found here on stackoverflow)
public class ImageUploadService extends HttpServlet {
private static final int MAX_FILE_SIZE = 1 * 1024 * 1024;
#Override
protected void doPost(final HttpServletRequest request,
final HttpServletResponse response) {
wlog("INFO: LA SERVLET é PARTITA");
boolean isMultipart = /* ServletFileUpload.isMultipartContent(request); */true;
if (isMultipart) {
wlog("INFO: IL CONTENUTO é MULTIPART");
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(MAX_FILE_SIZE);
try {
List<FileItem> items = upload.parseRequest(request);
wlog("INFO: LISTA PARTI " + Arrays.toString(items.toArray()));
Iterator<FileItem> iterator = items.iterator();
while (iterator.hasNext()) {
FileItem item = (FileItem) iterator.next();
if (!item.isFormField()) {
String fileName = item.getName();
String root = getServletContext().getRealPath("/");
File path = new File(root + "/fileuploads");
if (!path.exists()) {
boolean status = path.mkdirs();
}
File uploadedFile = new File(path + "/" + fileName);
item.write(uploadedFile);
wlog("INFO: SALVATO FILE SU DISCO");
}
}
wlog("FINE SERVLET");
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void wlog(String s) {
System.out.println("UPLOAD SERVLET " + s);
}
}
This servlet is correctly invoked, and the method doPost executes when I perform form.submit() on the client, but the problem is, upload.parseRequest always returns an empty list.
As I seached here on SO the solution, I found that the main cause for this behaviour is that the request has already been parsed before, but, as you can see from the code I posted, I never parse the request before .parseRequest().
I'm really getting mad tryng to understand where the problem stands, as all the solutions suggested so far haven't worked.
Thanks to everyone who will help spot the error..
(If it helps, I may post the client-side code, although I don't think that the issue lies there)
EDIT: inserted client code
private void inserisciSegnalazioneOK() {
final PopupPanel inserisciSegnalazionePopup = new PopupPanel();
VerticalPanel inseriscisegnalazioneholder = new VerticalPanel();
final FormPanel textform = new FormPanel();
final FormPanel uploadform = new FormPanel();
Button inseriscisegnalazionebtn = new Button("INSERISCI SEGNALAZIONE");
VerticalPanel textholder = new VerticalPanel();
VerticalPanel uploadholder = new VerticalPanel();
final Segnalazione segnalazione = new Segnalazione();
final ListBox lbcat = new ListBox();
for (String s : listaCategorie)
lbcat.addItem(s);
final TextBox descrizione = new TextBox();
final GoogleSuggestBox gsb = new GoogleSuggestBox();
final FileUpload fu = new FileUpload();
textholder.add(new Label("scegli la categoria della segnalazione"));
textholder.add(lbcat);
textholder.add(new Label("inserisci una descrizione testuale"));
textholder.add(descrizione);
textholder.add(new Label("inserisci l'indirizzo della segnalazione"));
textholder.add(gsb);
uploadholder.add(new Label(
"se puoi, allega una foto della segnalazione"));
uploadholder.add(fu);
textform.add(textholder);
uploadform.add(uploadholder);
inseriscisegnalazioneholder.add(textform);
inseriscisegnalazioneholder.add(uploadform);
inseriscisegnalazioneholder.add(inseriscisegnalazionebtn);
inserisciSegnalazionePopup.setWidget(inseriscisegnalazioneholder);
inseriscisegnalazionebtn.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
// TODO Auto-generated method stub
segnalazione.setCategoria(lbcat.getItemText(lbcat
.getSelectedIndex()));
segnalazione.setDescrizione(descrizione.getText());
segnalazione.setIndirizzo(gsb.getText());
segnalazione.setUtente(username);
log("INFO: upload del file " + fu.getFilename());
textform.submit();
uploadform.submit();
}
});
uploadform.setAction(GWT.getModuleBaseURL() + "imageUpload");
uploadform.setEncoding(FormPanel.ENCODING_MULTIPART);
uploadform.setMethod(FormPanel.METHOD_POST);
uploadform.addSubmitHandler(new FormPanel.SubmitHandler() {
#Override
public void onSubmit(SubmitEvent event) {
// TODO Auto-generated method stub
if (fu.getFilename().length() == 0) {
Window.alert("Non hai eseguito l'upload di nessuna immagine");
event.cancel();
}
}
});
textform.addSubmitHandler(new FormPanel.SubmitHandler() {
#Override
public void onSubmit(SubmitEvent event) {
// TODO Auto-generated method stub
dataLayerService.inserisciSegnalazione(segnalazione,
new AsyncCallback<Boolean>() {
#Override
public void onFailure(Throwable caught) {
// TODO Auto-generated
// method stub
caught.printStackTrace();
}
#Override
public void onSuccess(Boolean result) {
// TODO Auto-generated
// method stub
if (result) {
Window.alert("Inserimento avvenuto con successo");
inserisciSegnalazionePopup.hide();
gc.getLatLng(segnalazione.getIndirizzo(),
new LatLngCallback() {
#Override
public void onFailure() {
// TODO
// Auto-generated
// method
// stub
}
#Override
public void onSuccess(
LatLng point) {
// TODO
// Auto-generated
// method
// stub
Marker m = new Marker(point);
map.addOverlay(m);
listaMarker.add(m);
}
});
} else
Window.alert("L'inserimento ha avuto esito negativo");
}
});
}
});
inserisciSegnalazionePopup.setAutoHideEnabled(true);
inserisciSegnalazionePopup.setGlassEnabled(true);
inserisciSegnalazionePopup.center();
}
You have to set a name to your FileUpload if you want the field to be sent out to the server.
BTW, why are you using a FormPanel for your "data" form? Why aren't you simply calling the RPC from the submit button's click? or alternatively, why aren't you putting everything in the same uploadForm and processing it all at once (data and uploaded file) on the server in your upload servlet?

Upload image to server in GWT project using Servlet

I am developing a GWT application which, among its other functions, permits the user to upload an image file and to store it on the server.
So far, that's what I've done..
SERVLET
public class ImageUploadService extends HttpServlet {
private static final int MAX_FILE_SIZE = 1 * 1024 * 1024;
public void doPost(HttpServletRequest request, HttpServletResponse response) {
wlog("INFO: è partita la servlet");
if (!ServletFileUpload.isMultipartContent(request))
wlog("ERR: non è multipart!");
ServletFileUpload fileUpld = new ServletFileUpload();
try {
wlog("INFO: itero file");
FileItemIterator fileIt = fileUpld.getItemIterator(request);
while (fileIt.hasNext()) {
wlog("INFO: trovato file");
FileItemStream fileStream = fileIt.next();
BufferedInputStream in = new BufferedInputStream(
fileStream.openStream(), 4096);
BufferedOutputStream out = new BufferedOutputStream(
new FileOutputStream("immagineSegnalazione.jpg"));
byte[] buf = new byte[MAX_FILE_SIZE];
int byteRead;
while ((byteRead = in.read(buf, 0, MAX_FILE_SIZE)) >= 0) {
out.write(buf, 0, byteRead);
}
in.close();
out.flush();
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void wlog(String s) {
System.out.println("UPLOAD SERVLET " + s);
}
}
MODULE ON CLIENT SIDE
[...]
PopupPanel inserisciSegnalazionePopup = new PopupPanel();
final FormPanel uploadForm = new FormPanel();
uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
uploadForm.setMethod(FormPanel.METHOD_POST);
inserisciSegnalazionePopup.setAutoHideEnabled(true);
VerticalPanel holder = new VerticalPanel();
holder.add(new Label("se puoi, allega una foto della segnalazione"));
final FileUpload fu = new FileUpload();
uploadForm.add(fu);
holder.add(uploadForm);
uploadForm.setAction(GWT.getModuleBaseURL() + "imageUpload");
Button inviaBtn = new Button("INVIA SEGNALAZIONE");
inviaBtn.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
// TODO check file is image and size and other stuff
uploadForm.submit();
}
});
holder.add(inviaBtn);
[...]
..plus I've rightly made the changes needed on web.xml
The Servlet is correctly called and the method doPost() starts, but the FileItemIterator is always empty, as if there were no files at all..
Can someone guess what's wrong? I can't really see where's the mistake
Thank you in advance
just guessing I would say the request is parsed somewhere befor you use it. Try taking a look at that question and the answer to it, it seems to like it was nearly the same problem.
Sarajog
Have you tried this ??
Iterator<FileItem> iterator = upload.parseRequest(request).iterator();
The solution is...
Simply add .setName() to the FileUpload widget

Listen to msmq queue

Following the is the code I have for listening to messages from Windows form.
I have noticed that when I click on send it sends a message to MyQueue but at that time I was hoping the event mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e) should get called but it is not, in other words I am trying to subscribe to MyQueue from Windows form. Just wondering if I am missing something in the code:
public class Form1 : System.Windows.Forms.Form
{
public System.Messaging.MessageQueue mq;
public static Int32 j=0;
public Form1()
{
// Required for Windows Form Designer support
InitializeComponent();
// Queue Creation
if(MessageQueue.Exists(#".\Private$\MyQueue"))
mq = new System.Messaging.MessageQueue(#".\Private$\MyQueue");
else
mq = MessageQueue.Create(#".\Private$\MyQueue");
mq.ReceiveCompleted += new ReceiveCompletedEventHandler(mq_ReceiveCompleted);
mq.BeginReceive();
}
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void btnMsg_Click(object sender, System.EventArgs e)
{
// SendMessage(Handle, 1, 0, IntPtr.Zero);
System.Messaging.Message mm = new System.Messaging.Message();
mm.Body = txtMsg.Text;
mm.Label = "Msg" + j.ToString();
j++;
mq.Send(mm);
}
void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
//throw new NotImplementedException();
}
private void btnRcv_Click(object sender, System.EventArgs e)
{
System.Messaging.Message mes;
string m;
try
{
mes = mq.Receive(new TimeSpan(0, 0, 3));
mes.Formatter = new XmlMessageFormatter(new String[] {"System.String,mscorlib"});
m = mes.Body.ToString();
}
catch
{
m = "No Message";
}
MsgBox.Items.Add(m.ToString());
}
}
See MSDN's example on how to use the ReceiveCompletedEventHandler .
They have a console app where the Main() does the same as your Form1(), but your handler doesn't have any code. You've said it doesn't call back into your event delegate, but perhaps check your queue name is correct on the constructor.
Consider using MSDN's sample code in a new console app to test your environment first, then go back to your WinForms code with any lessons learned.
private static void MyReceiveCompleted(Object source,
ReceiveCompletedEventArgs asyncResult)
{
MessageQueue mq = (MessageQueue)source;
Message m = mq.EndReceive(asyncResult.AsyncResult);
Console.WriteLine("Message: " + (string)m.Body);
mq.BeginReceive();
return;
}
If you want to inspect the queue and get a message on the click of a button, you can simply move the statement mq.BeginReceive(); to the btnRcv_Click() in place of .Receive();