Currently I am facing a problem which I am unable to solve after a lot of work and search, I asked a similar question before but didn't got any reply maybe because I didn't asked it correctly so I deleted that question.
Ok I am downloading emails using MailBEE.net Objects library and it is working fine except that if downloading method is called again while a previous call is still in downloading phase then two copies of messages start to download which is wrong.
on an ASP.net page I am calling an ASHX handler that downloads the emails
public class sync : IHttpHandler {
public void ProcessRequest(HttpContext context)
{
ApplicationData.layer Functions = new layer();
context.Response.ContentType = "text/text";
int messageCount = Convert.ToInt16(context.Request.QueryString["messageCount"]);
if (Functions.SyncMail("email", "user", "password", "pop.gmail.com", messageCount) == "Successful")
{
context.Response.Write("New Messages Downloaded.");
}
//context.Response.Write("Hello World");
}
}
I am calling the above ASHX handler using Jquery from another (ASPX) page
<script type="text/javascript">
$(document).ready(function() {
asyncLoad();
});
function asyncLoad() {
document.getElementById("CustomerDetails").innerHTML = "<img alt='' src='Images/ajax-loader.gif' />" + " <span>Downloading New Messages...</span>";
$('#CustomerDetails').load("sync.ashx?messageCount=" + "10");
callAgain();
}
function callAgain() {
setInterval(asyncLoad, 20000);
}
</script>
The purpose is to keep on calling sync.ashx after some time (The 20000 delay) to check new messages, the problem is if one call of sync.ashx is busy in downloading messages and a new call is made during this time, it starts to download identical copies of messages since it does not find the ids of emails in database which previous call is going to make.
I need some sort of mutually exclusive access, that if once call is busy in downloading messages then another call should not be made.
Something like
if(IsAlreadyDownloading == False)
{
Functions.SyncMail(params)
}
Where IsAlreadyDownloading is a global flag or mutex that should be set True once one call start downloading and be set false once it finish downloading or some exception has occurred indicating that another call can be made safely.
Since it is an ASP.net application we don't know when user will navigate away from the page which start download call and when it will navigate back to that page so another call to download handler should be made or not.
I don't know if I explained it properly or not but I hope someone will understand. Thank you.
Finally after much hair pulling and head scratching I managed to solve this problem, I don't know if it's the best solution but at least it is working properly now, if you know a better solution please share it here, thanks.
Here is my solution.
I used global.asax to declare application level global variable named as follows
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
Application["IsAlreadyDownloading"] = false;
}
The purpose is to mimic mutex like behavior and for that I left sync.ashx file and made another an aspx file, the reason for shifting from ashx file is access application level variable IsAlreadyDownloading which is unavailable in a generic handler. The code of aspx file is as follows
<%# Page Language="C#" %>
<%# Import Namespace="ApplicationData" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
int messageCount = Convert.ToInt16(Request.QueryString["messageCount"]);
ApplicationData.layer Functions = new layer();
try
{
if (!Convert.ToBoolean(Application["IsAlreadyDownloading"]))
{
Application["IsAlreadyDownloading"] = true;
if (Functions.SyncMail("email", "user", "password", "pop.gmail.com", messageCount) == "Successful")
{
Response.Write("New Messages Downloaded.");
Application["IsAlreadyDownloading"] = false;
}
else
{
Response.Write("<p>Unable to download some messages</p>");
Application["IsAlreadyDownloading"] = false;
}
}
}
finally
{
Application["IsAlreadyDownloading"] = false;
}
Response.End();
}
</script>
No matter how many times we make call to this page the method will not work as it will find IsAlreadyDownloading = true if another call of method is busy in work, as soon as it will finish it will again set IsAlreadyDownloading = false so a new call can acquire it.
Hope this help someone in similar problem.
server
Related
I have an AjaxButton. The event fires, and I'm testing a scenario where I need to add a feedback and return without committing the change. I add the feedback at the page level (our feedback only shows page level messages...others are showing on component level feedback panels). I add the WebMarkupContainer that contains the feedback panel to the target. This exact thing works on every other button on the page.
But for this button, which happens to be the only one where defaultformprocessing is not false, the feedback doesn't show. To the user's view, nothing happens except our processing veil appears and then disappears. If I hit submit again, THEN the message and feedback are shown. I stuck a timestamp on it to see if it was showing the one from the 2nd request or the 1st. It's from the 1st.
What's more, a breakpoint in the feedback's filter shows that the filter was never called in the 1st request, but is called BEFORE the event processing on the 2nd request. It accepts the message as intended.
I set defaultformprocessing to FALSE on this button as a test, and in fact, messages suddenly work. But of course, that also means the form doesn't get processed. Can someone help me square this circle?
AjaxButton:
add(new AjaxButton("btnCreateRequest", getForm()) {
#Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
//stuff happens
target.add(getFeedbackPanelForAjax());
String date = new Date().toGMTString();
System.out.println("ADDING MESSAGE - " + date);
getPage().error("This is a message! " + date);
return;
}
#Override
public void onError(AjaxRequestTarget target, Form<?> form) {
getPage().error("There was an error processing your request");
target.add(getFeedbackPanelForAjax());
target.add(form);
}
}.setVisible(enabled));
UPDATE:
getFeedbackPanelForAjax returns the web markup container that the feedback resides in. I've also tried adding the feedback directly to the target.
public Component getFeedbackPanelForAjax() {
return (Component) getForm().get("feedbackWmc");
}
Where the feedback is added:
feedback = new FRFeedbackPanel("feedback") {
#Override
public boolean isVisible() {
if(anyMessage()){
return true;
} else {
return false;
}
}
};
// feedback container
WebMarkupContainer feedbackWmc = new WebMarkupContainer("feedbackWmc");
getForm().add(feedbackWmc.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
feedbackWmc.add(feedback.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
I can say that through debugging, I put a breakpoint in anyMessage() and it returns false in this case at the same time that getPage().getFeedbackMessages() returns the message correctly. I commented out this override of isVisible() and indeed, the message shows. The problem is, that it means the artifacts of the feedback panel show when there are no messages as well, which is not what we want.
This anyMessage() solution works perfectly when I'm in an event that is defaultformprocessing=false. I suppose I could do an anyMessage() || getPage().getFeedbackMessages(), but my understanding was that anyMessage was supposed to find if there was ANY message in the hierarchy for this panel. Is that not so?
I assume you cannot replicate the problem in a small quickstart?
One idea: I've seen similar problems when the FeedbackPanel collects its messages too early, i.e. before you add the error to the page.
FeedbackMessagesModel keeps the messages to render until the end of the request - maybe some of your code triggers this by accessing the messages model.
I have a working ProgressMonitorDialog, but I want to make sure that I am setting it up correctly.
First the Code:
Method to create Dialog
public void startProgressBar() {
try {
new ProgressMonitorDialog(getShell()).run(true, true,
new ProgressBarThread());
}
catch (InvocationTargetException e) {
MessageDialog.openError(getShell(), "Error", e.getMessage());
}
catch (InterruptedException e) {
MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
}
}
Class File
class ProgressBarThread implements IRunnableWithProgress {
private static final int TOTAL_TIME = 1000;
public ProgressBarThread() {
}
public void run(IProgressMonitor monitor) throws InvocationTargetException,InterruptedException {
monitor.beginTask("Creating PDF File(s): Please wait.....", IProgressMonitor.UNKNOWN);
for (int total = 0; total < TOTAL_TIME ; total++) {
Thread.sleep(total);
monitor.worked(total);
if (total == TOTAL_TIME / 2) monitor.subTask("Please be patient... Operation should finish soon.");
}
monitor.done();
}
}
Method that calls the ProgressBar and runs a Pdf file creation Operation
private void startSavePdfOperation() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
startProgressBar();
}
});
saveOp = new AplotSaveOperation(appReg.getString("aplot.message.SAVETOPDF"), "PDF", session);
saveOp.addOperationListener(new MyOperationListener(this) {
public void endOperationImpl() {
java.io.File zipFile = null;
try {
AplotSaveResultsParser.SaveResult saveResults = saveOp.getSaveResults();
if (saveResults != null) {
ETC..... ETC......
Questions:
Being the ProgressMonitorDialog is a GUI, it needs to be executed in a
Display.getDefault().asyncExec?
If the ProgressMonitorDialog is running in a separate thread, how does it know to close when the operation is finsihed?
Is there any relationship between the progressbar and the operation?
I am correct in assuming that the for loop in the ProgressBarThread class is basically the timer that keeps the monitor open?
Is there a way to increase the speed of the ProgressMonitorDialog's indicator, also can you remove the cancel button?
This is what I am thinking is happening currently.
I am starting the progress bar just before I start the PDF Operation Listener
See startSavePdfOperation() Above
The progress bar is running as unknown, but using a for loop to keep the progress bar dialog open, while the operation is running on a thread in the background.
See Class ProgressBarThread above
When the PDF operation completes the listener operation class closes the base GUI dialog.
public void endOperation() {
try {
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
w.close();
}
});
}
}
I am not sure what is happening to the ProgressBarThread monitor?
Is this Possible?
When the PDF Operation starts, the ProgressMonitorDialog opens and starts the indicator. OK with keeping it unknown.
When the PDF Operation completes, the monitor closes, then the base Dialog
I am just wanting to open progress bar dialog that will inform the user that their request is working in the background.
As stated the above code works, but I am afraid by letting the closing of Base GUI, destroy my Progress Thread and Monitor is not good practice.
First of all, in your ProgressBarThread#run() you should use monitor.worked(1). You don't need to set the total worked but increment it by the amount of work done, since the last time it was called.
Q1. Yes it needs to be executed in the display thread
Q2. Normally the work that needs to be done is actually performed in the runnable that is passed to the progress monitor dialog so that you can accurately report the amount of progress made. So your operation (if it is a synchronous call) should be called from within ProgressBarThread#run() so that you call monitor.worked(1) only when one file processing is complete.
Q3. What kind of operation are you running, perhaps it already supports showing progress bar, and you just need to invoke the right API. Is it an IUndoableOperation?
Q4. As I said this approach is problematic because you can never accurately report the progress and close the dialog only when the operation is completed. But if this is the only choice you have, then you can just save the monitor reference somewhere so that it is accessible to the other thread. Once monitor.done() is called, your ProgressBarThread#run() should return, the dialog will close.
Q5. You can remove the cancel button by passing the correct parameter to ProgressMonitorDialog#run(..):
new ProgressMonitorDialog(getShell()).run(true, false, new ProgressBarThread());
For the rest of the questions I can better answer if I know what kind of operation (what API) you are using.
New to GWT but I love it so far. I do have a problem that's easy to reproduce. It is a big problem for me because I want to create a GWT Module for PubNub - a utility we use internally.
I created a demo project to test out encapsulation and I have found an interesting problem with ScriptInjector/Pubnub.
At first I followed the PubNub instructions. NOTE: I have included my keys for my test account. Feel free to use them.
Following the instructions I put these two items in the html file in the GWT project (with my keys specified):
<div pub-key="pub-b8b75fbd-c4cf-4583-bab9-424af7a7f755" sub-key="sub-5e843c94-1193-11e2-bba9-b116c93082cf" ssl="off" origin="pubsub.pubnub.com" id="pubnub"></div>
<script src="http://cdn.pubnub.com/pubnub-3.1.min.js"></script>
When I do this, I can use JSNI to access pubnub. It all works great.
What doesn't work is if I delete the tag here and inject the script instead with the following code. I know the script injects because I can see the success message and I can see the script in Developer tools in Chrome.
ScriptInjector.fromUrl("http://cdn.pubnub.com/pubnub-3.1.js").setCallback(
new Callback<Void, Exception>() {
public void onFailure(Exception reason) {
Window.alert("Script load failed.");
}
public void onSuccess(Void result) {
Window.alert("Script load success.");
}
}).inject();
I feel this must be somehow related to accessing the DOM with the delayed script, or because the script is not a part of the DOM. It's trying to access the setup div and it's not able to...(just my guess)
Any thoughts? I need to move the items out of the html file because I need to modularize this project for use in other larger projects. Any help would be appreciated.
(PS, I have tried to create html widgets as well, and add them in EntryPoint. This also adds the tag to the page based on my browsing in Developer Tools in Chrome, but it fails to work just as ScriptInjector fails.)
EDIT: Here is as simple a project as I can make to demo the problem:
html file:
above the closing body tag:
<div pub-key="pub-b8b75fbd-c4cf-4583-bab9-424af7a7f755" sub-key="sub-5e843c94-1193-11e2-bba9-b116c93082cf" ssl="off" origin="pubsub.pubnub.com" id="pubnub"></div>
<script src="http://cdn.pubnub.com/pubnub-3.1.min.js"></script>
<script src="pubnubWrapper.js"></script>
pubnubWrapper.js (basically what's at the pubnub website):
function subToPubNub(){
PUBNUB.subscribe({
channel : "hello_world", // CONNECT TO THIS CHANNEL.
restore : false, // STAY CONNECTED, EVEN WHEN BROWSER IS CLOSED
// OR WHEN PAGE CHANGES.
callback : function(message) { // RECEIVED A MESSAGE.
alert(message);
},
disconnect : function() { // LOST CONNECTION.
alert(
"Connection Lost." +
"Will auto-reconnect when Online."
)
},
reconnect : function() { // CONNECTION RESTORED.
alert("And we're Back!")
},
connect : function() { // CONNECTION ESTABLISHED.
PUBNUB.publish({ // SEND A MESSAGE.
channel : "hello_world",
message : "Hi from PubNub."
})
}
})
}
ScriptTest.java:
public class ScriptTest implements EntryPoint {
public void onModuleLoad() {
//add a button to sub to pubnub
Button subButton = new Button("Sub");
//add the event handler for button
subButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
//sub to pubnub
callSub();
}
});
RootPanel.get().add(subButton);
}
public native void callSub() /*-{
//call my wrapper to pubnub
$wnd.subToPubNub();
}-*/;
}
This all works as is.
If you remove the pubnub script from the html file and add it with script injector, it fails. If you add the script to the gwt.xml file, it fails.
Any Ideas?
Can you post your JSNI code?
I bet you are accessing PubNub via the $wnd variable right?
If you put the script tags in your module's xml file the pubnub code will be loaded in the host's page window (you can check with Chrome DeveloperTools).
ScriptInjector by default won't load it there but in the GWT namespace.
So in order to load it into the host's window namespace you have to pass the TOP_WINDOW to the ScriptInjector
ScriptInjector.fromUrl("http://cdn.pubnub.com/pubnub-3.1.js").setCallback(
new Callback<Void, Exception>() {
public void onFailure(Exception reason) {
Window.alert("Script load failed.");
}
public void onSuccess(Void result) {
Window.alert("Script load success.");
}
}).setWindow(ScriptInjector.TOP_WINDOW).inject();
I'm using filepicker.makeDropPane to play around with some simple uploads. One thing that I cannot find in the docs at filepicker.io's web documentation is a method for canceling an upload that is in progress.
Intuitively I feel that the onStart function should be passed an additional parameter. An object that represents the upload that has a cancel() function which when called would immediately cancel the file uploads. Something like this does not seem to be available.
we don't actually have this functionality yet, but it makes sense. I'll take a look at adding something along these lines and let you know
Here's an ugly hack I figured out to protect against unwanted returned files as well some other fancy stuff around progress and multiple files etc. You definitely want to use a static js file include so it doesn't get changed on you and break this.
Use this in your progress handler:
var event = event || window.event;
// For firefox, go and grab the XHR progress event object.
if (typeof event == 'undefined' || event == null) {
if (typeof arguments.callee.caller.arguments[0] == 'object') {
event = arguments.callee.caller.arguments[0];
}
else {
event = arguments.callee.caller.arguments.callee.caller.arguments.callee.caller.arguments[0];
}
}
var sUploadId;
if (event.type.toLowerCase() == 'progress') {
// if we haven't already tagged this XHR object (one per file), tag it now
// if we receive further progress from this file, it will already have been tagged
if (!('id' in event.currentTarget)) {
sUploadId = goUploadProgress.files.length;
event.currentTarget.id = sUploadId;
goUploadProgress.files.push({id: sUploadId, total:event.total});
}
else {
sUploadId = event.currentTarget.id;
}
// get the loaded bytes for this file
goUploadProgress.files[sUploadId].loaded = event.loaded;
}
else {
// ignore readystatechange events
return;
}
I modified this to make more sense for this context, so I may have made a logical mistake, but this is the gist. You can get the event in Firefox by looking up the call stack, and you can append an id to each file's XHR upload object, which will exist until it finishes.
I repeat, this is a hack! Don't trust that it won't break.
I am using a sandboxed solution (sharepoint 2010 project is on office 365 hence using sandboxed solution) and want to go from one page to another on a button click event. This is achieved by javascript but the operations in the click event are not being performed.
For example, I assign the javascript on page load to the desired event then the event performs the redirection without going into the code which is inside the event.
The javascript used for redirection is :
string redirectURL = "http://ksreejit:32512/sites/SplTeam/Pages/QuizMasterDashboard.aspx";
btnCancel.Attributes.Add("OnClick", "javascript:{window.location='" + redirectURL + "';return false;}");
And the event code is:
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (ViewState["QuestionID"].ToString() != string.Empty)
{
SaveDetails(ViewState["QuestionID"].ToString());
foreach (Control contrl in this.Controls)
{
contrl.Visible = false;
}
}
else
{
SaveDetails();
foreach (Control contrl in this.Controls)
{
contrl.Visible = false;
}
}
Label lblMessage = new Label();
lblMessage.Visible = true;
lblMessage.Text = "The Question is successfully saved and sent to reviewer for reviewing. Thanks for uploading.";
}
As you can see the redirection works for btnCancel successfully. I have not assigned it for btnSubmit cos it will then only redirect and will not go to the above specified code.Tried microsoft help they were also clueless.Answers will be appreciated.the project requirement has been modified. long time no answers please check more. Thanks in advance.
Add this code in your button click
string redirectURL = "http://ksreejit:32512/sites/SplTeam/Pages/QuizMasterDashboard.aspx";
this.Controls.Add(new LiteralControl("<script>window.location.href='" + redirectURL + "';</script>"));
For your btnSubmit button, don't add the attribute like you did for your btnCancel.
And then simply add a Response.Redirect(...); in your event method.
... lblMessage.Text = "The Question is successfully saved and sent to reviewer for reviewing. Thanks for uploading.";
Response.Redirect("http://ksreejit:32512/sites/SplTeam/Pages/QuizMasterDashboard.aspx");