Final update (please see comments)
I have given up on implementing my own QR generator due to GAE limitations. The former Google Charts API services still can be used, and also replicated using ZXing's servlet. For more details, see this link. Thank you for the answers.
Update 2 (see original question below)
So I dug into the source of ZXing and they seem to use BufferedImage in all of their processes. My question now could be phrased as:
Is there any way to use ZXing with Google App Engine?
Is there any way to generate a QR code in a servlet that could be
deployed to Google App Engine?
Update (see original question below)
The following line causes the error apparently:
MatrixToImageWriter.writeToStream(encoded, "png", outs);
It seems to be using BufferedImage. Is it possible to convert a BitMatrix to a byte[] without doing this step?
Original question
I am trying to create a servlet on Google App Engine to return a QR code with given parameters. So far I have created solutions both with QRGen and ZXing which work perfectly when testing in App Engine local development mode. My problem is that both of these implementations fail after I deploy my servlet to App Engine, saying either
Could not initialize class
com.google.apphosting.runtime.security.shared.stub.java.awt.image.BufferedImage
or
java.awt.Image is a restricted class. Please see the Google App Engine
developer's guide for more details.
I don't understand completely how these tools work internally, what I know that java.awt.image classes are not on the Class whitelist. My question is that is there any way to get around this security feature, and actually return a QR code from a servlet. Here is my latest implementation (which works fine in development mode, but also fails on a deployed servlet) using ZXing (it seems to offer more options than QRGen):
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
String returnString = "myString";
Writer writer = new QRCodeWriter();
BitMatrix encoded = null;
try
{
encoded = writer.encode(returnString, BarcodeFormat.QR_CODE, 300, 300);
}
catch (WriterException ex)
{
Logger.getLogger(QRService.class.getName()).log(Level.SEVERE, null, ex);
}
ByteArrayOutputStream outs = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(encoded, "png", outs);
byte[] out = outs.toByteArray();
Blob qrImage = new Blob(out);
resp.setContentType("image/jpeg");
resp.getOutputStream().write(qrImage.getBytes());
}
Here, look into the Google Charts API
https://developers.google.com/chart/infographics/docs/qr_codes
It seems it allows you to create a QR code with simple HTTP GET request. To create an HTTP GET request in App Engine, try this:
https://developers.google.com/appengine/docs/java/urlfetch/
Related
I'm working on removing Protected View from a series of PDFs, and am trying to use the iText library within VBA. My main issue at this point is that I have no idea what method to use, and the iText documentation is pretty dense.
I'm also feeling my way forward on calling the iText library from VBA, so any help on syntax to do this is also appreciated, though I'm sure I could get there myself if I knew which method to call...
Currently, I've got:
Dim program As WshExec
program = Shell("Java.exe -jar " & mypath & "\itext-5.5.6\itextpdf-5.5.6.jar")
'Debug.print program returns a value here, so this line works.
'I'm thinking I need something like:
'Set program = RunProgram("Java.exe -jar " & mypath & "\itext-5.5.6\itextpdf-5.5.6.jar", & _
methodName, param1)
I've been using the following questions to get me this far...
Calling Java library (JAR) from VBA/VBScript/Visual Basic Classic
Microsoft Excel Macro to run Java program
Desired functionality is to have an unprotected PDF sitting in a folder on mypath.
The jar you are trying to run is not an executable jar. iText is a library that be used in a Java application by adding itextpdf-5.5.6.jar to the CLASSPATH. If you don't write any Java code, then the jar won't do a thing, hence your Shell() and your RunProgram() methods are useless: there is nothing to execute.
Moreover: from your question, it is far from certain that you have a Java environment on your machine. You are working in a VBA environment, which makes one wonder why you'd use the Java version of iText. Have you tried using iTextSharp, which is the .NET version of iText (written in C#)?
Take a look at this tutorial: Programmatically Complete PDF Form Fields using Visual Basic and the iTextSharp DLL
In this tutorial, we take an existing PDF, we fill out a form, and we get another PDF based on the original PDF, but with extra data. You can easily adapt the code so that it takes an existing PDF, doesn't add anything to the PDF, but saves the original PDF without its passwords, as is explained in my answer to How can I decrypt a PDF document with the owner password?
If you combine what you can learn from my Java code:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader.unethicalreading = true;
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
}
with what you learn from the form filling tutorial, you get something like this (provided that you use the iTextSharp DLL instead of the iText jar):
Dim pdfTemplate As String = "c:\Temp\PDF\encrypted.pdf"
Dim newFile As String = "c:\Temp\PDF\decrypted.pdf"
PdfReader.unethicalreading = true
Dim pdfReader As New PdfReader(pdfTemplate)
Dim pdfStamper As New PdfStamper(pdfReader, New FileStream(
newFile, FileMode.Create))
pdfStamper.Close()
pdfReader.Close()
IMPORTANT: this will only remove the password if the file is only protected with an owner password (which is what I assume when you talk about protected view). If the file is protected in any other way, you'll have to clarify. Also note that the parameter unethicalreading is not without meaning: make sure that you're not doing unethical by removing the protection.
I was having to manipulate protected PDF files using iText.
I just put in my pom.xml the following dependency and nothing more.
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.59</version>
</dependency>
The idea is to build a proprietary Java back end document system using Office Web Apps.
We have created the WOPI client which allows us to view/edit PowerPoint and Excel web app documents but we can only view Word Documents.
In order to edit Word Web App documents you need to implement MS-FSSHTTP.
It appears there is no information about how to actually do this in code. Has anyone performed this or would know how?
recently my team and I have implemented a WOPI-Host that supports viewing and editing of Word, PPT and Excel documents. You can take a look at https://github.com/marx-yu/WopiHost which is a command prompt project that listens on the 8080 port and enables editing and viewing of word documents though the Microsoft Office Web Apps.
We have implemented this solution in a webApi and it works great. Hope this sample project will help you out.
After requested, I will try and add code samples to clarify the way to implement it based on my webApi implementation, but their is a lot of code to implement to actually make it work properly.
First things first, to enabled editing you will need to capture Http Posts in a FilesController. Each posts that concern the actual editing will have the header X-WOPI-Override equal to COBALT. In these post you will find out that the InputStream is and Atom type. Based on the MS-WOPI documentation, in your response you will need to include the following headers X-WOPI-CorrelationID and request-id.
Here is the code of my webApi post method (it is not complete since I'm still implementing that WOPI protocol).
string wopiOverride = Request.Headers.GetValues("X-WOPI-Override").First();
if (wopiOverride.Equals("COBALT"))
{
string filename = name;
EditSession editSession = CobaltSessionManager.Instance.GetSession(filename);
var filePath = HostingEnvironment.MapPath("~/App_Data/");
if (editSession == null){
var fileExt = filename.Substring(filename.LastIndexOf('.') + 1);
if (fileExt.ToLower().Equals(#"xlsx"))
editSession = new FileSession(filename, filePath + "/" + filename, #"yonggui.yu", #"yuyg", #"yonggui.yu#emacle.com", false);
else
editSession = new CobaltSession(filename, filePath + "/" + filename, #"patrick.racicot", #"Patrick Racicot", #"patrick.racicot#hospitalis.com", false);
CobaltSessionManager.Instance.AddSession(editSession);
}
//cobalt, for docx and pptx
var ms = new MemoryStream();
HttpContext.Current.Request.InputStream.CopyTo(ms);
AtomFromByteArray atomRequest = new AtomFromByteArray(ms.ToArray());
RequestBatch requestBatch = new RequestBatch();
Object ctx;
ProtocolVersion protocolVersion;
requestBatch.DeserializeInputFromProtocol(atomRequest, out ctx, out protocolVersion);
editSession.ExecuteRequestBatch(requestBatch);
foreach (Request request in requestBatch.Requests)
{
if (request.GetType() == typeof(PutChangesRequest) && request.PartitionId == FilePartitionId.Content)
{
//upload file to hdfs
editSession.Save();
}
}
var responseContent = requestBatch.SerializeOutputToProtocol(protocolVersion);
var host = Request.Headers.GetValues("Host");
var correlationID = Request.Headers.GetValues("X-WOPI-CorrelationID").First();
response.Headers.Add("X-WOPI-CorrelationID", correlationID);
response.Headers.Add("request-id", correlationID);
MemoryStream memoryStream = new MemoryStream();
var streamContent = new PushStreamContent((outputStream, httpContext, transportContent) =>
{
responseContent.CopyTo(outputStream);
outputStream.Close();
});
response.Content = streamContent;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentLength = responseContent.Length;
}
As you can see in this method I make use of CobaltSessionManager and CobaltSession which are used to create and manage editing sessions on the Cobalt protocol. You will also need a what I call CobaltHostLockingStore which is used to handle the different requests when communicating with the Office Web App server in the edition initialization.
I won't be posting the code for these 3 classes since they are already coded in the sample github project I posted and that they are fairly simple to understand even though they are big.
If you have more questions or if it's not clear enough don't hesitate to comment and I will update my post accordingly.
Patrick Racicot, provided great answer. But i had problem saving docx(exception in CobaltCore.dll), and i even started using dotPeak reflector trying to figure it out.
But after i locked editSession variable in my WebApi method everything started working like magic. It seems that OWA is sending requests that should be handled as a chain, not in parallel as usually controller method acts.
I'm hoping the answer to this question is quite simple, but I can't get it working after looking at the Azure Java API documentation.
I am trying to create an empty CloudBlockBlob, which will have blocks uploaded to it at a later point. I have successfully uploaded blocks before, when the blob is created upon the first block being uploaded, but I can't seem to get anything other than ("the specified blob does not exist") when I try to create a new blob without any data and then access it. I require this because in my service, a call is first made to create the new blob in Azure, and then later calls are used to upload blocks (at which point a check is made to see if the blob exists). Is it possible to create an empty blob in Azure, and upload data to it later? What have I missed?
I've not worked with Java SDK so I may be wrong but I tried creating an empty blob using C# code (storage client library 2.0) and if I upload an empty input stream an empty blob with zero byte size is created. I did something like the following:
CloudBlockBlob emptyBlob = blobContainer.GetBlockBlobReference("emptyblob.txt");
using (MemoryStream ms = new MemoryStream())
{
emptyBlob.UploadFromStream(ms);//Empty memory stream. Will create an empty blob.
}
I did look at Azure SDK for Java source code on Github here: https://github.com/WindowsAzure/azure-sdk-for-java/blob/master/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java and found this "upload" function where you can specify an input stream. Try it out and see if it works for you.
I am using JavaFX media player to play an mp3 file using following code
new MediaPlayer(new Media(FileObject.toURI().toString())).play();
However now I have a requirement that I have the mp3 byte data in memory instead of an File Object. The reason is the mp3 file is encrypted and then shipped along with the program. Hence I need to decrypt the mp3 file in memory or input stream.
I could decrypt the mp3 file to an temporary file in temp directory but this would be a performance overhead and the audio content would be insecure.
From the Media Javadoc
Only HTTP, FILE, and JAR URLs are supported. If the provided URL is invalid then an exception will be thrown. If an asynchronous error occurs, the error property will be set. Listen to this property to be notified of any such errors.
I'm not personally familiar with JavaFX, but that would suggest to me that without resorting to nasty hacks, you're not going to be able to read media directly from memory. Normally for this kind of URI only interface I'd suggest registering a custom UrlStreamHandler and a custom protocol that reads from memory. But assuming that JavaDoc is correct, the JavaFX uses it's own resolution so presumably this will not work.
Given this then I suspect the only way to make this work is to provide access to the in-memory MP3 over HTTP. You could do this using Jetty or any similar embeddable servlet container. Something along the following lines:
1) Start Up Jetty as per Quick Start Guide
2) Register a servlet that looks something like below. This servlet will expose your in-memory data:
public class MagicAccessServlet extends HttpServlet {
private static final Map<String, byte[]> mediaMap = new ConcurrentHashMap();
public static String registerMedia(byte[] media) {
String key = UUID.randomUUID().toString();
mediaMap.put(key, media);
return key;
}
public static deregisterMedia(String key) {
mediaMap.remove(key);
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
String key = req.get("key");
byte[] media = mediaMap.get(key);
resp.setContentLength(media.length);
resp.getOutputStream().write(media);
}
}
Then you can access from within your application using an http url. E.g. something like
MagicAccessServlet.registerMedia(decodedMp3);
new MediaPlayer(new Media("http://localhost:<port>/<context>/<servlet>?key=" + key)).play();
Unfortunately as the Media constructor stands I see no easy way to do this other than the temporary file approach. Note that while I agree the performance would have an overhead, if the files aren't too big (most mp3 files generally aren't) then the overhead should be minimal in this sense. And technically, decoding the content to memory also renders it insecure (though admittedly much harder to extract.)
One slightly crazy approach I did think of was to use sockets. You could setup a separate part of your application which decrypts the unencrypted content and then streams the raw mp3 bytes over a certain port on localhost. You could then provide this as a HTTP URI to the Media constructor.
[edit]
I've removed my convoluted and badly malformed question so that it doesn't detract from the very neat and correct answer beneath. Given the (surprising) difficulty of finding an on-line example for doing this incredibly common task, I hope Yoni gets a few more up-ticks for his response.
So... the question in a nutshell...
How do I use Apache.Commons to upload a file to some destination. I'm using it in Android and uploading to a PHP script, but obviously it can work from any Java program and to any HTTP based listener.
From the api of MultipartRequestEntity:
File f = new File("/path/fileToUpload.txt");
PostMethod filePost = new PostMethod("http://host/some_path");
Part[] parts = {
new StringPart("param_name", "value"),
new FilePart(f.getName(), f)
};
filePost.setRequestEntity(
new MultipartRequestEntity(parts, filePost.getParams())
);
HttpClient client = new HttpClient();
int status = client.executeMethod(filePost);
I don't think you need the content-disposition part, that is used for the other direction (when the browser downloads a file and needs to know what to do with it).
getParams.setParameter is optional. You can also set it directly on the HttpClient instance.
AFAIK, the order of setting request headers is irrelevant, as long as they are all set before you set the request body.