I'm using the upload component of vaadin(7.1.9), now my trouble is that I'm not able to restrict what kind of files that can be sent with the upload component to the server, but I haven't found any API for that purpose. The only way is that of discarding file of wrong types after the upload.
public OutputStream receiveUpload(String filename, String mimeType) {
if(!checkIfAValidType(filename)){
upload.interruptUpload();
}
return out;
}
Is this a correct way?
No, its not the correct way. The fact is, Vaadin does provide many useful interfaces that you can use to monitor when the upload started, interrupted, finished or failed. Here is a list:
com.vaadin.ui.Upload.FailedListener;
com.vaadin.ui.Upload.FinishedListener;
com.vaadin.ui.Upload.ProgressListener;
com.vaadin.ui.Upload.Receiver;
com.vaadin.ui.Upload.StartedListener;
Here is a code snippet to give you an example:
#Override
public void uploadStarted(StartedEvent event) {
// TODO Auto-generated method stub
System.out.println("***Upload: uploadStarted()");
String contentType = event.getMIMEType();
boolean allowed = false;
for(int i=0;i<allowedMimeTypes.size();i++){
if(contentType.equalsIgnoreCase(allowedMimeTypes.get(i))){
allowed = true;
break;
}
}
if(allowed){
fileNameLabel.setValue(event.getFilename());
progressBar.setValue(0f);
progressBar.setVisible(true);
cancelButton.setVisible(true);
upload.setEnabled(false);
}else{
Notification.show("Error", "\nAllowed MIME: "+allowedMimeTypes, Type.ERROR_MESSAGE);
upload.interruptUpload();
}
}
Here, allowedMimeTypes is an array of mime-type strings.
ArrayList<String> allowedMimeTypes = new ArrayList<String>();
allowedMimeTypes.add("image/jpeg");
allowedMimeTypes.add("image/png");
I hope it helps you.
Can be done.
You can add this and it will work (all done by HTML 5 and most browsers now support accept attribute) - this is example for .csv files:
upload.setButtonCaption("Import");
JavaScript.getCurrent().execute("document.getElementsByClassName('gwt-FileUpload')[0].setAttribute('accept', '.csv')");
I think it's better to throw custom exception from Receiver's receiveUpload:
Upload upload = new Upload(null, new Upload.Receiver() {
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
boolean typeSupported = /* do your check*/;
if (!typeSupported) {
throw new UnsupportedImageTypeException();
}
// continue returning correct stream
}
});
The exception is just a simple custom exception:
public class UnsupportedImageTypeException extends RuntimeException {
}
Then you just simply add a listener if the upload fails and check whether the reason is your exception:
upload.addFailedListener(new Upload.FailedListener() {
#Override
public void uploadFailed(Upload.FailedEvent event) {
if (event.getReason() instanceof UnsupportedImageTypeException) {
// do your stuff but probably don't log it as an error since it's not 'real' error
// better would be to show sth like a notification to inform your user
} else {
LOGGER.error("Upload failed, source={}, component={}", event.getSource(), event.getComponent());
}
}
});
public static boolean checkFileType(String mimeTypeToCheck) {
ArrayList allowedMimeTypes = new ArrayList();
allowedMimeTypes.add("image/jpeg");
allowedMimeTypes.add("application/pdf");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
allowedMimeTypes.add("image/png");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.presentationml.presentation");
allowedMimeTypes.add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
for (int i = 0; i < allowedMimeTypes.size(); i++) {
String temp = allowedMimeTypes.get(i);
if (temp.equalsIgnoreCase(mimeTypeToCheck)) {
return true;
}
}
return false;
}
I am working with Vaadin 8 and I there is no change in Upload class.
FileUploader receiver = new FileUploader();
Upload upload = new Upload();
upload.setAcceptMimeTypes("application/json");
upload.setButtonCaption("Open");
upload.setReceiver(receiver);
upload.addSucceededListener(receiver);
FileUploader is the class that I created that handles the upload process. Let me know if you need to see the implementation.
Related
So I'm completely lost on this one, it might be obvious solution or I'm just trying somethin that's not possible but here it is.
I have two classes one is being used as e listener class and second one is the one that handles queue(i will only include relevant code).
Handler class:
public void check() {
for (Queueable queueable : queue) {
if (!doesReceiverHavePlayers(queueable)) continue;
}
}
private boolean doesReceiverHavePlayers(Queueable queueable) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerCount");
out.writeUTF(queueable.getReceiver());
Player player = Iterables.getFirst(Bukkit.getOnlinePlayers(), null);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
return /*response*/ > 0;
}
Listener class:
#Override
public void onPluginMessageReceived(String channel, #NotNull Player player, byte[] message) {
if (!channel.equals("BungeeCord")) return;
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subChannel = in.readUTF();
switch (subChannel) {
case "PlayerCount":
int response = in.readInt();
break;
}
}
The check method is called every 5 seconds and doesReceiverHavePlayers requests player count from a certain server to see if there are any players on it, but the 'response' arrives in the listener class onPluginMessageReceived method. But as you can see I'm trying to use response in the doesReceiverHavePlayers method and return boolean value. Is there any way I can achieve this and how should I do it?
In onPluginMessageReceived store the result in a ConcurrentHashMap and then lookup the value in doesReceiverHavePlayers instead of making a blocking call.
Something like this:
ConcurrentHashMap<String, Integer> playerCounts = new ConcurrentHashMap<>();
void onPluginMessageReceived() {
playerCounts.put(subChannel, response);
}
boolean doesReceiverHavePlayers() {
return playerCounts.get(queueable.getReceiver()) > 0;
}
I had an issue where Text to Speech would not speak anything. I realised this was due to the fact that I was attempting to call 'Speak()' before TTS had initialised.
I need to wait until TTS has initialised, so that I can call 'Speak()' successfully. I thought doing something along the lines of this would work:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTTSInitialised = true;
} else {
Log.e("TTS", "Initialisation Failed!");
}
}
...
while(!mTTSInitialised){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But this fails to initialise at all. Is there a way to do this effectively?
The initialisation of the Text to Speech engine is asynchronous, which is why you realised you have to 'wait' for it to complete, before requesting that it processes an utterance.
Even when it eventually initialises successfully, it can be subsequently killed by the system, or it can of course fail to initialise, so you always need to be ready to handle a request to speak, where the engine isn't prepared.
Add the following helper class
public class PendingTTS {
private String pendingUtterance;
private int pendingQueueType;
public String getPendingUtterance() {
return this.pendingUtterance;
}
public void setPendingUtterance(#NonNull final String pendingUtterance) {
this.pendingUtterance = pendingUtterance;
}
public int getPendingQueueType() {
return this.pendingQueueType;
}
public void setPendingQueueType(final int pendingQueueType) {
this.pendingQueueType = pendingQueueType;
}
}
Assuming you're using an Activity, you need to declare the following variables:
private volatile PendingTTS pendingTTS;
private static final int MAX_INIT_ATTEMPTS = 4;
private volatile int initCount;
and initialise the Text to Speech object in onCreate()
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
In your onInitListener you would check if there is any pending speech:
#Override
public void onInit(final int status) {
switch (status) {
case TextToSpeech.SUCCESS:
initCount = 0;
// Set up tts stuff
tts.setOnUtteranceProgressListener(YOURprogressListener);
if (pendingTTS != null) {
// We have pending speech, process it and check the result
int speechResult = tts.speak(pendingTTS.getPendingUtterance(),pendingTTS.getPendingQueueType(),
// remaining tts variables here)
switch (speechResult){
case TextToSpeech.SUCCESS:
// Result was successful
pendingTTS = null;
break;
case TextToSpeech.ERROR:
// Speech failed
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
} else {
// there was nothing to process
}
break;
case TextToSpeech.ERROR:
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
I've glued the above together from my code - where the speech and initialisation methods are all separated, but I tried to give you an overview above of everything you need to handle.
Elsewhere in your code, when you make a tts.speak(//stuff here) request, you need to check the result as demonstrated above, to make sure it was successful. Again, in my code, this is separated into one single method. If it does fail, you need to set the PendingTTS parameters prior to attempting to initialise again:
pendingTTS = new PendingTTS();
pendingTTS.setPendingQueueType(// your queue type);
pendingTTS.setPendingUtterance(// your utterance);
It is is successful, make sure pendingTTS is set to null.
The overall design is that if the initialisation failed, it will attempt to initialise again, up to the maximum allowed attempts. If the speech fails, it will attempt to initialise the engine again, firstly setting the PendingTTS parameters.
Hope you managed to follow that.
Hmm..
Not a very good idea.
You can try to add the text to the TTS queue and let it do it's work. This snippet can be inside button click, etc as:
tts.speak(toSpeak, TextToSpeech.QUEUE_ADD, null);
Small tutorial that would help.
I am trying to provide capability to upload file in my vaadin application
protected Upload questionImageUpload = new Upload("Upload question", questionReceiver);
questionImageUpload.addFinishedListener(new Upload.FinishedListener() {
#Override
public void uploadFinished(Upload.FinishedEvent event) {
boolean hasLock = VaadinSession.getCurrent().hasLock();
button.setEnabled(false);
}
});
But, in my FinishListener.uploadFinished(), if I modify some UI element (in above, I disable a button), the modification does not get applied.
I assumed that this method may be invoked in a non UI thread so I checked whether VaadinSession is available by putting a breakpoint in uploadFinished above. But, VaadinSession.getCurrent() didn't return null. Also hasLock is also true.
What could be the reason?
I am running this vaadin application on Google App Engine (still running locally inside IntelliJ IDEA). Could that be the reason behind this?
File upload is done as a POST request to the server, containing the file data. When the upload is complete, Upload.FinishedListeners are called at the end of that POST request. While all thread locals are set up correctly, this is not a UI update request (or UIDL request) and the response which is sent to the browser only contains a text that informs the browser that the upload finished. Any UI updates done will be queued until another request asks for them.
Because of this, you need to either use #Push, so that the UI changes are pushed immediately to the client through the push channel, or enable polling at the latest when starting the upload, so that the poll request will pick up the UI changes.
I actually accomplish what you want to do with a SuccedListener. I have a code which updates an embedded component with picture uploaded. You can look at the code and take a cue from it. It can also disable the button. You can correct it not optimised but it works
public class PicUploader extends Upload implements SucceededListener, Receiver {
private static final long serialVersionUID = 1L;
File file;
public String fileName;
final String LOCATION = "/home/###";
Embedded image = new Embedded();
TextField field;
public PicUploader(Embedded image, String caption) {
this.image = image;
this.addSucceededListener(this);
this.setReceiver(this);
this.setCaption(caption);
this.setIcon(FontAwesome.UPLOAD);;
}
public PicUploader(Embedded image, TextField field) {
this.image = image;
this.addSucceededListener(this);
this.setReceiver(this);
this.field = field;
this.setButtonCaption(""+FontAwesome.UPLOAD);
this.setIcon(FontAwesome.UPLOAD);;
}
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
// TODO Auto-generated method stub
FileOutputStream stream = null;
try {
file = new File(LOCATION
+ "/Pictures/"
+ System.currentTimeMillis()
+ filename.substring(filename.length() - 4,
filename.length()));
fileName = file.getName();
System.out.println("This is the file name " + filename);
stream = new FileOutputStream(file);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
return stream;
}
#Override
public void uploadSucceeded(SucceededEvent event) {
// TODO Auto-generated method stub
image.setSource(new FileResource(file));
image.setVisible(true);
image.setWidth("150");
image.setHeight("200");
// float ratio = image.getHeight()/image.getWidth();
// image.setWidth(""+image.getWidth());
// image.setHeight(""+image.getHeight());
// field.setValue(getFileName());
this.setEnabled(false);
}
public String getFileName() {
return fileName;
}
}
I want to download a CSV file using Wicket, by implementing an AbstractResource. It looks something like this:
public class ExportCsvFileResource extends AbstractResource
{
#Override
protected AbstractResource.ResourceResponse newResourceResponse(IResource.Attributes attributes)
{
AbstractResource.ResourceResponse resourceResponse = new AbstractResource.ResourceResponse();
resourceResponse.setContentType("text/csv");
resourceResponse.setFileName("exported-contacts-file.csv");
resourceResponse.setTextEncoding("utf-8");
resourceResponse.setWriteCallback(new AbstractResource.WriteCallback()
{
#Override
public void writeData(IResource.Attributes attributes) throws IOException
{
OutputStream stream = attributes.getResponse().getOutputStream();
generateContentInBatches(stream);
}
});
return resourceResponse;
}
private void generateContentInBatches(OutputStream stream)
{
int numberOfChunks=//...
for (int i=0; i<numberOfChunks; i++)
{
byte[] contentChunk = retrieveContentFromBackend(i);
IOUtils.write(contentChunk, stream);
}
}
}
The problem is that, while the content is being generated with the retrieveContentFromBackend function (which is quite time consuming), the user interface is unresponsive. I click the buttons etc. but nothing happens, only after the file is done being generate can I use the interface again.
How do I avoid blocking the user interface while the file is being generated gradually?
Take a look at RequestMapperApplication and MapperDemoResourceReference from wicket-examples.
You can mount resource references:
mountResource("/print/${sheet}/${format}", new MapperDemoResourceReference());
To load such a resource without blocking the page, you'll have to render a link which triggers the resource directly:
add(new WebMarkupContainer("link")
{
#Override
protected void onComponentTag(ComponentTag tag)
{
super.onComponentTag(tag);
PageParameters parameters = new PageParameters();
parameters.add("sheet", "sheet1");
parameters.add("format", "A4");
tag.put("href", urlFor(new MapperDemoResourceReference(), parameters));
}
});
Here is an example of lazy loading:
http://www.wicket-library.com/wicket-examples/ajax/lazy-loading?1
I don't know how this works with your AbstractResource object but this should get you in the right direction.
I've met a problem and I've been struggling last 2 days. I have a compiled program that runs some simulations and visualizes the results in an SVG file. The file is replaced every 2 seconds with a new one, until the simulation is done.
Wanting to visualize the results, I made a java swing program which uses batik and JSVGCanvas to display the svg file and update it every 2 seconds.
The code I use is:
// In the main part of my code
svgCanvas = new JSVGCanvas();
oneLineInnerPanel.add("Center", svgCanvas);
(new Thread() {
#Override
public void run() {
try {
Thread.sleep(2000);
File f = new File("file_that_shows_simulation_still_running");
while (f.exists()) {
svgReloadButtonActionPerformed(null);
Thread.sleep(2000);
}
} catch (InterruptedException ex) {
Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
// -----------------------------------------------
private void svgReloadButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
svgCanvas.loadSVGDocument(SVGFile.toURL().toString());
} catch (MalformedURLException ex) {
Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
It works fine with the exception that every 30-40 updates, it happens that the loadSVGDocument tries to read the document while it's being written by the simulator and thus I get a jdialog error:
XML document structures must start and end within the same entity.
org.apache.batik.dom.util.SAXIOException: XML document structures must start and end within the same entity.
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:437)
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:349)
at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createDocument(SAXSVGDocumentFactory.java:200)
at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createSVGDocument(SAXSVGDocumentFactory.java:124)
at org.apache.batik.bridge.DocumentLoader.loadDocument(DocumentLoader.java:106)
at org.apache.batik.swing.svg.SVGDocumentLoader.run(SVGDocumentLoader.java:84)
Caused by: org.xml.sax.SAXParseException; systemId: file:/tmp/tempDir9189341730639722289/svgOut.svg; lineNumber: 272; columnNumber: 2; XML document structures must start and end within the same entity.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:431)
... 5 more
This doesn't affect the whole procedure, but it's ugly. I get 2-3 of these jdialogs throughout the simulation. I cannot lock the file I/O, because I don't have access to the simulator code. If I lock from java only, the simulator crashes saying it cannot access the file.
What I want is that if there is an error while loading the svg file to somehow catch it internally and not have a jdialog. I can accept missing an update every 30-40 times (60-80 secs).
Now, JSVGCanvas gives you the option to provide a useragent and overwrite the displayError() method to do as you like. I tried that but the dialogs still occur. The problem is that the dialogs are not produced by the svgUserAgent I provide but by an internal BridgeUserAgent:
public JSVGComponent(SVGUserAgent ua, boolean eventsEnabled,
boolean selectableText) {
super(eventsEnabled, selectableText);
svgUserAgent = ua;
userAgent = new BridgeUserAgentWrapper(createUserAgent());
addSVGDocumentLoaderListener((SVGListener)listener);
addGVTTreeBuilderListener((SVGListener)listener);
addSVGLoadEventDispatcherListener((SVGListener)listener);
if (updateOverlay != null)
getOverlays().add(updateOverlay);
}
public void loadSVGDocument(String url) {
String oldURI = null;
if (svgDocument != null) {
oldURI = svgDocument.getURL();
}
final ParsedURL newURI = new ParsedURL(oldURI, url);
stopThenRun(new Runnable() {
public void run() {
String url = newURI.toString();
fragmentIdentifier = newURI.getRef();
loader = new DocumentLoader(userAgent);
nextDocumentLoader = new SVGDocumentLoader(url, loader);
nextDocumentLoader.setPriority(Thread.MIN_PRIORITY);
Iterator it = svgDocumentLoaderListeners.iterator();
while (it.hasNext()) {
nextDocumentLoader.addSVGDocumentLoaderListener
((SVGDocumentLoaderListener)it.next());
}
startDocumentLoader();
}
});
}
Can anyone help me get out of this mess, please?
Thanks in advance!
Finally solved the issue. Extended JSVGCanvas, override the createUserAgent() method to provide a bridgeuseragent of my own. This useragent extends the JSVGCanvas user agent but overrides the displayError methods. Here's the code:
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.util.XMLConstants;
/**
*
* #author
*/
public class myJSVGCanvas extends JSVGCanvas{
#Override
protected UserAgent createUserAgent() {
return new myCanvasUserAgent();
}
protected class myCanvasUserAgent extends CanvasUserAgent
implements XMLConstants {
/**
* Displays an error message in the User Agent interface.
*/
#Override
public void displayError(String message) {
if (svgUserAgent != null) {
super.displayError(message);
} else {
System.out.println(message);
// JOptionPane pane =
// new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
// JDialog dialog =
// pane.createDialog(myJSVGCanvas.this, "ERROR");
// dialog.setModal(false);
// dialog.setVisible(true); // Safe to be called from any thread
}
}
/**
* Displays an error resulting from the specified Exception.
*/
#Override
public void displayError(Exception ex) {
if (svgUserAgent != null) {
super.displayError(ex);
} else {
ex.printStackTrace();
// JErrorPane pane =
// new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
// JDialog dialog = pane.createDialog(myJSVGCanvas.this, "ERROR");
// dialog.setModal(false);
// dialog.setVisible(true); // Safe to be called from any thread
}
}
}
}
Hope it helps somebody. If anyone has a better idea for dealing with the problem, than just hiding it, I'd be glad to hear it!