from deprecated Blobstore File API to serving blobs - java

I'm using Google App Engine Endpoints in connection with my Android app. In one of my endpoints I have a method that takes an image - encoded in Base64 - which is then stored in the Blobstore. Retrieving the image is done by the serving URL of the Google ImageService.
So, I got two problems. First, the Blobstore File API that I'm using is deprecated. Second, the call is very slow because the server works synchronously when storing the blob and later on serving-url and blob-key.
So my question is, how can I change the code to use the Blobstore as proposed by Google (servlets) but keep using my very nice Endpoint in the Android code. Is there a way to keep using that method without using HttpRequest classes?
In short:
Can I keep my client-side call to the Endpoint or do I need to change that code?
If I can keep my client/server side interface of the endpoint, how can I redirect to Blobstore to asynchronously save the image and then call another servlet where I can store the blobkey and serving-url?
Here's my code.
The entity that is send from Android client to Google app engine.
#Entity
public class Image {
#Id
private int id = -1;
private byte[] data;
private String mimeType;
private int width;
private int height;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
The server-side endpoint implementation:
#Api(name = "imageEndpoint", namespace = #ApiNamespace(ownerDomain = "example.com", ownerName = "example.com", packagePath = "myPackage")}
public class ImageEndPoint extentds BaseEndPoint {
#ApiMethod(name = "updateImage")
public Void updateImage(final User user,
final Image image) {
String blobKey = FileHandler.storeFile(
location != null ? location.getBlobKey() : null,
image.getData(), image.getMimeType(),
LocationTable.TABLE_NAME + "." + locationId, logger);
ImagesService imageService = ImagesServiceFactory
.getImagesService();
// image size 0 will retrieve the original image (max: 1600)
ServingUrlOptions options = ServingUrlOptions.Builder
.withBlobKey(new BlobKey(blobKey)).secureUrl(true)
.imageSize(0);
String servingUrl = imageService.getServingUrl(options);
// store BlobKey & ServingUrl in Database
return null;
}
}
The Android Java code to call the endpoint on the Google App Engine.
public void uploadBitmap(Bitmap image)
{
ImageEndpoint.Builder endpointbuilder = creator.create(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(),
new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest arg0)
throws IOException {
}
});
endpointbuilder.setApplicationName(GoogleConstants.PROJECT_ID);
ImageEndpoint endpoint = endpointbuilder.build();
// set google credidentials
// encode image to byte-rray
byte[] data = ....
// create cloud contet
Image content = new Image();
content.setWidth(image.get_width());
content.setHeight(image.get_height());
content.setMimeType("image/png");
content.setData(Base64.encodeBase64String(data));
// upload content (but takes too much time)
endpoint.updateImage(content);
}

This is not solution to your problem that you explained, but you can go for this GCS:
There are lot of Google Cloud Storage java api's available, you can upload the image or any file, and you can make it public and get the image url or just get JSON api from GCS such that you can download the image or any file content.
Ex: https://github.com/pliablematter/simple-cloud-storage
You can use Google Cloud Storage Java API for sending the data to cloud and
Using Google Cloud Storage JSON api in android to retrieve the data.
https://cloud.google.com/appengine/docs/java/googlestorage/

Related

How to Load WhatsApp Sticker from firebase?

Problem Description
How to Load Stickers Packs from firebase?
Links
Already I've been through -
https://github.com/idoideas/StickerMaker-for-Whatsapp
https://github.com/viztushar/stickers-internet
Well, you have to make a class with the sticker properties, a provider and a couple more things before loading the stickers from firebase(you can easily know how to retrieve data from firebase, it's the same for any data, so im going to skip that step)..
A dynamic WAStickers app should have following Characteristics:
Content Provider for necessary Details
It should Send an Intent to Whatsapp Sharing necessary details about the Sticker Pack All the
images must be in (or converted to) webp format
Why it should have a Content Provider?
A content provider is a class that sits between an application and its data source, and its job is to provide easy access to the underlying data source. This data can also be accessed by other applications on your device.
To provide necessary information about the StickerPack to WhatsApp you need to create a class called StickerPack which will hold the following parameters.
class StickerPack implements Parcelable {
String identifier;
String name;
String publisher;
String trayImageFile;
final String publisherEmail;
final String publisherWebsite;
final String privacyPolicyWebsite;
final String licenseAgreementWebsite;
String iosAppStoreLink;
private List<Sticker> stickers;
private long totalSize;
String androidPlayStoreLink;
private boolean isWhitelisted;
StickerPack(String identifier, String name, String publisher, String trayImageFile, String publisherEmail, String publisherWebsite, String privacyPolicyWebsite, String licenseAgreementWebsite) {
this.identifier = identifier;
this.name = name;
this.publisher = publisher;
this.trayImageFile = trayImageFile;
this.publisherEmail = publisherEmail;
this.publisherWebsite = publisherWebsite;
this.privacyPolicyWebsite = privacyPolicyWebsite;
this.licenseAgreementWebsite = licenseAgreementWebsite;
}
}
For additional information about this class follow the Link.
This class also contains an ArrayList of Stickers, where Sticker is defined by the following class.
package com.example.samplestickerapp;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.List;
class Sticker implements Parcelable {
String imageFileName;
List<String> emojis;
long size;
Sticker(String imageFileName, List<String> emojis) {
this.imageFileName = imageFileName;
this.emojis = emojis;
}
protected Sticker(Parcel in) {
imageFileName = in.readString();
emojis = in.createStringArrayList();
size = in.readLong();
}
public static final Creator<Sticker> CREATOR = new Creator<Sticker>() {
#Override
public Sticker createFromParcel(Parcel in) {
return new Sticker(in);
}
#Override
public Sticker[] newArray(int size) {
return new Sticker[size];
}
};
public void setSize(long size) {
this.size = size;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(imageFileName);
dest.writeStringList(emojis);
dest.writeLong(size);
}
}
Creating the Content Provider
For creating the content provider, first step is to:
Get permission to use the ContentProvider:
In the Android Manifest we should ask for a read/write permission to use the content provider. It’s a security feature which informs the user of what the app actually does.
<provider
android:name=".StickerContentProvider"
android:authorities="${contentProviderAuthority}"
android:enabled="true"
android:exported="true"
android:readPermission="com.whatsapp.sticker.READ" />
Where ${contentProviderAuthority} will be replaced by the authority name of your content provider.
Create a Class that extends ContentProvider
URI — Uniform Resource Identifier: URI is used to specifically identify or give the location of some data on your phone.
This location is how you know exactly what type of data we’re querying for. The location is build from 3 parts:
(1) content:// — The content provider prefix
(2) The content authority — specifies which Content Provider to use
(3) Specific
data — a string that identifies exactly what data in the Content
Provider we’re interesting in accessing.
In our Content Provider we need to mention 4 URI’S as mentioned here.
First, In the onCreate method of your ContentProvider class, create a URI Matcher object and add the URI’s to the object. Before going through the below code snippet read about Uri Matcher from the here.
Now since you are familiar with URI matcher you must be familiar with how to use it
First, we build a tree of Uri Matcher object.
Then we pass the Url to getType function which matches it against our URI
Let’s perform the first step here.
private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static final String METADATA = "metadata";
private static final int METADATA_CODE = 1;
private static final int METADATA_CODE_FOR_SINGLE_PACK = 2;
private static final int STICKERS_CODE = 3;
static final String STICKERS_ASSET = "stickers_asset";
private static final int STICKERS_ASSET_CODE = 4;
private static final int STICKER_PACK_TRAY_ICON_CODE = 5;
#Override
public boolean onCreate() {
final String authority = BuildConfig.CONTENT_PROVIDER_AUTHORITY;
if (!authority.startsWith(Objects.requireNonNull(getContext()).getPackageName())) {
throw new IllegalStateException("your authority (" + authority + ") for the content provider should start with your package name: " + getContext().getPackageName());
}
MATCHER.addURI(authority, METADATA, METADATA_CODE);
MATCHER.addURI(authority, METADATA + "/*", METADATA_CODE_FOR_SINGLE_PACK);
MATCHER.addURI(authority, STICKERS + "/*", STICKERS_CODE);
for (StickerPack stickerPack : getStickerPackList()) {
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + stickerPack.trayImageFile, STICKER_PACK_TRAY_ICON_CODE);
for (Sticker sticker : stickerPack.getStickers()) {
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + sticker.imageFileName, STICKERS_ASSET_CODE);
}
}
return true;
}
Here in the above method we have added a Uri pattern to our MATCHER object, now we need to match this pattern and return the exact UrI which will the location of sticker data on our device. Next the Url hit by WhatsApp is passed to the getType function to match it against our Uri’s and return the specific location of data on our device.
#Override
public String getType(#NonNull Uri uri) {
final int matchCode = MATCHER.match(uri);
switch (matchCode) {
case METADATA_CODE:
return "vnd.android.cursor.dir/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + METADATA;
case METADATA_CODE_FOR_SINGLE_PACK:
return "vnd.android.cursor.item/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + METADATA;
case STICKERS_CODE:
return "vnd.android.cursor.dir/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + STICKERS;
case STICKERS_ASSET_CODE:
return "image/webp";
case STICKER_PACK_TRAY_ICON_CODE:
return "image/png";
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
Next, depending upon the Url we call the query method which will match the Uri and return a cursor object for the specific Uri.
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final int code = MATCHER.match(uri);
if (code == METADATA_CODE) {
return getPackForAllStickerPacks(uri);
} else if (code == METADATA_CODE_FOR_SINGLE_PACK) {
return getCursorForSingleStickerPack(uri);
} else if (code == STICKERS_CODE) {
return getStickersForAStickerPack(uri);
} else {
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
Cursors are iterators that provide read/write access to the data of a Content Provider.
See the getPackForAllStickerPacks(), getCursorForSingleStickerPack() and getStickerPackInfo() function from here. To know the type of data to be provided by the Cursor Object.
Congratulations!! By now you have reached your first milestone. So far we have learnt:
What are Content Providers?
What type of Data do we send via ContentProviders?
How do we process the Uri’s to give a specific Cursor object?
If you can answer these questions then Congrats!! You have done a wonderful job. If not then I would suggest you to read about ContentProviders and UriMatcher’s to get a proper understanding.
After that, you just need to load the content from firebase, which should have the same structure on your class.
Source: Link

How to pass data from vaadin webapp to C# GUI app

I have webapp in Vaadin Framework 8. I have Windows GUI app in C#.
The gui app is using WebBrowser component to display webapp. WebBrowser component is internally using IE11 core through ActiveX. I can successfully load and display the webapp in the gui app browser component.
I need to pass data from webapp to the gui app.
The webapp has many rows loaded on server side, only few are displayed in grid. I want to pass all data from webapp to gui app in some format (csv or json).
I have tryed some approaches, but I wasn't successfull.
[Approach 1]
Webapp: attach downloadable resource (csv) to Link with predefined id using FileDownloader. Download by user mouse click works fine, file save dialog pops up and data are downloaded successfully.
Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
FileDownloader downloader = new FileDownloader(resource);
downloader.extend(link);
Page.getCurrent().getJavaScript().addFunction("test", new JavaScriptFunction() {
#Override
public void call(JsonArray arguments) {
Page.getCurrent().getJavaScript()
.execute("document.getElementById('myId').click()");
}
});
Gui app: raise onClick event on link and capture WebBrowser.FileDownload event, capture WebBrowser.Navigate event.
I have failed to raise onClick event from C# using:
HtmlElement el = webBrowser.Document.GetElementById("myId");
el.RaiseEvent("onClick");
el.InvokeMember("click");
webBrowser.Document.InvokeScript("document.getElementById('myId').click();", null);
webBrowser.Document.InvokeScript("test", null);
Result:
WebBrowser.FileDownload event doesn't work (is fired but can't capture url nor data), capture WebBrowser.Navigate event works partialy (can see resource url, but can't download data using byte[] b = new WebClient().DownloadData(e.Url);).
[Approach 2]
Similar to approach 1. I tryed to get resource url, put the direct url to Link and download the resource in c# using direct link. I can construct the same resource url as is used by browser to download data when user clicks the link.
Extended file downloader that keeps resource, key and connector:
public class ExtendedFileDownloader extends FileDownloader {
private String myKey;
private Resource myResource;
private ClientConnector myConnector;
public ExtendedFileDownloader(StreamResource resource, ClientConnector connector) {
super(resource);
myConnector = connector;
}
#Override
protected void setResource(String key, Resource resource) {
super.setResource(key, resource);
myKey = key;
myResource = resource;
}
public String getResourceUrl() {
ResourceReference ref =
ResourceReference.create(
myResource,
(myConnector != null) ? myConnector : this,
myKey);
String url = ref.getURL();
return url;
}
}
In view:
// fix app://path... urls to /<base-path>/path urls
private String fixResourceReferenceUrl(String resourceReferenceUrl) {
String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
String uiBaseUrl = ui.getUiRootPath();
String fixedUrl = uiBaseUrl + "/" + resourceReferencePath;
return fixedUrl;
}
Link link2 = new Link("Data2");
link2.setId("myId2");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource, this);
String fixedResourceUrl = fixResourceReferenceUrl(downloader.getResourceUrl());
link2.setResource(new ExternalResource(fixedResourceUrl));
Result:
The data cannot be downloaded using this link, server error 410 or NotFound errors.
Any Ideas ? Any other approaches to try ?
I have finally solved the problem. The solution is very close to approach 2.
The resource url is passed in element with custom attribute. C# WebClient needs to set cookies from WebBrowser and Referer HTTP headers. The data can be successfully downloaded by C# app.
Element attribute in vaadin webapp can be set using Vaadin-addon Attributes.
Cookies in C# app can be retrieved using this solution.
// Fix resource urls begining with app://
public String fixResourceReferenceUrl(String resourceReferenceUrl) {
try {
String uiRootPath = UI.getCurrent().getUiRootPath();
URI location = Page.getCurrent().getLocation();
String appLocation = new URIBuilder()
.setScheme(location.getScheme())
.setHost(location.getHost())
.setPort(location.getPort())
.setPath(uiRootPath)
.build()
.toString();
String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
String fixedUrl = appLocation + "/" + resourceReferencePath;
return fixedUrl;
}
catch (Exception e) {
return null;
}
}
In view (using ExtendedFileDownloader from above):
Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource);
downloader.extend(link);
Attribute attr = new Attribute("x-my-data", fixResourceReferenceUrl(downloader.getResourceUrl()));
attr.extend(link);
link.setVisible(true);
In C# app:
[DllImport("wininet.dll", SetLastError = true)]
public static extern bool InternetGetCookieEx(
string url,
string cookieName,
StringBuilder cookieData,
ref int size,
Int32 dwFlags,
IntPtr lpReserved);
private const Int32 InternetCookieHttponly = 0x2000;
public static String GetUriCookies(String uri)
{
// Determine the size of the cookie
int datasize = 8192 * 16;
StringBuilder cookieData = new StringBuilder(datasize);
if (!InternetGetCookieEx(uri, null, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
{
if (datasize < 0)
return null;
// Allocate stringbuilder large enough to hold the cookie
cookieData = new StringBuilder(datasize);
if (!InternetGetCookieEx(
uri,
null, cookieData,
ref datasize,
InternetCookieHttponly,
IntPtr.Zero))
return null;
}
return cookieData.ToString();
}
private void button_Click(object sender, EventArgs e)
{
HtmlElement el = webBrowser.Document.GetElementById("myId");
String url = el.GetAttribute("x-my-data");
String cookies = GetUriCookies(url);
WebClient wc = new WebClient();
wc.Headers.Add("Cookie", cookies);
wc.Headers.Add("Referer", WEB_APP_URL); // url of webapp base path, http://myhost/MyUI
byte[] data = wc.DownloadData(url);
}

xmpp server is giving some int response on user creation how can i get that display in android application

i am creating a android application which can create and login felicity for the xmpp server. but my question is the server setup such a way on creation of new user it will return a int value i need to display that in android application. could you please help me how to get that int value. how to capture the server response..?? thank you in advance
I have already tried some of the links but not very useful
xmpp server is giving some int response on user creation how can i get that display in android application
First create a API to register a user.
Upon registration the server should send you a JSON response code as :
{
"id" : "1"
"error": false,
}
To read the response in your application you can use AsyncTask, Volley, Ion.
Here is example to use ION.
Following code will send a registration request to your server and will receive JSON response as above.
if (AppUtilities.isInternetConnected(this)) {
final Builders.Any.B builder = Ion.with(this).load("your.registration.url.com");
if (BuildConfig.DEBUG) {
builder.setLogging(TAG, Log.VERBOSE);
}
builder.setHeader(ApiConstants.HEADER_KEY_ACCEPT, ApiConstants.HEADER_ACCEPT_VALUE)
.setBodyParameter("username", username)
.setBodyParameter("password", password)
.as(RegistrationResponse.class)
.setCallback(mRegistrationCallback);
} else {
// Do something..
}
Create a RegistrationResponse.class
public class RegistrationResponse {
#SerializedName("id")
private int id;
#SerializedName("error")
private boolean error;
public boolean isError() {
return error;
}
public int getID() {
return id;
}
}
After creating of the model class of Registration response that you are going to recieve create a Callback like this.
private FutureCallback<RegistrationResponse> mRegistrationCallback= new FutureCallback<RegistrationResponse>() {
#Override
public void onCompleted(Exception exception, RegistrationResponse serverResponse) {
if (null == exception) {
int idFromServer = serverResponse.getID();
//idFromServer contains the integer value you were looking for.
//To get the boolean value you can do this.
boolean responseError = serverResponse.isError();
}
}
};
Hope this will help.

How to get profile image url from Facebook with spring-social?

I use spring-social-facebook to interact with Graph API (1.0.3.RELEASE if it's metter). And I can't find any operation to retrieve profile's image url. I found only operations which return array of bytes and they are not very convenient for the implementation.
Does any kind of operation which retrieves image url exist in Spring Social?
If not, is there any 'tidy' workaround for this?
Thanks!
Finally, I didn't find any mention of profile picture url in spring social
My solution:
Initially I planned to extend UserOperations (FacebokTemplate.userOperations) class and add new method. But it's a package-level class and doens't visible outside.
So I decided to create my own template class extending FacebookTemplate and implement the method in this way:
public String fetchPictureUrl(String userId, ImageType imageType) {
URI uri = URIBuilder.fromUri(GRAPH_API_URL + userId + "/picture" +
"?type=" + imageType.toString().toLowerCase() + "&redirect=false").build();
JsonNode response = getRestTemplate().getForObject(uri, JsonNode.class);
return response.get("data").get("url").getTextValue();
}
i just ran into same issue, hope this will help someone else
Connection<Facebook> connection = userConnectionRepository.findPrimaryConnection(Facebook.class);
connection.createData().getImageUrl()
You could take the miniature picture in this way :
"http://graph.facebook.com/" + fbUser.getId() + "/picture?type=square"
In social API you have ability just to fetch the image binary file:
byte[] profileImage = facebook.userOperations().getUserProfileImage(imageType);
To get URL you need to have something custom (as mentioned in the post above).
I took the part of code from Facebook Social API (see Facebook template source code for fetchImage) and the following utility class:
public final class FacebookUtils {
private static final String PICTURE_PATH = "picture";
private static final String TYPE_PARAMETER = "type";
private static final String WIDTH_PARAMETER = "width";
private static final String HEIGHT_PARAMETER = "height";
private FacebookUtils() {
}
public static String getUserProfileImageUrl(Facebook facebook, String userId, String width, String height, ImageType imageType) {
URIBuilder uriBuilder = URIBuilder.fromUri(facebook.getBaseGraphApiUrl() + userId + StringUtils.SLASH_CHARACTER + PICTURE_PATH);
if (imageType != null) {
uriBuilder.queryParam(TYPE_PARAMETER, imageType.toString().toLowerCase());
}
if (width != null) {
uriBuilder.queryParam(WIDTH_PARAMETER, width.toString());
}
if (height != null) {
uriBuilder.queryParam(HEIGHT_PARAMETER, height.toString());
}
URI uri = uriBuilder.build();
return uri.toString();
}
}

How to download images in playframework jobs?

I have a playframework Job class like this:
public class ImageDownloader extends Job {
private String[] urls;
private String dir;
public ImageDownloader(){}
public ImageDownloader(String[] urls,String dir){
this.urls = urls;
this.dir = dir;
}
#Override
public void doJob() throws Exception {
if(urls!=null && urls.length > 0){
for (int i = 0; i < urls.length; i++) {
String url = urls[i];
//Dowloading
}
}
}
}
Play(1.2.4) has lots of amazing tools to make things easy.
So i wonder whether there's a way to make the downloading easy and beautiful in play ?
There is a built-in HTTP client in Play.
With it, you can do HTTP requests like this:
HttpResponse res = WS.url("http://www.stackoverflow.com").get();
You can then get the content of the response in, for example, stream format:
InputStream is = res.getStream();

Categories