I am using the gwt-plus-v1-0.2-alpha API to:
Allow Google login
Fetch Signed in user's information
Google login works, but fetching the user's information fails with a
Cannot call method 'newHttpRequest' of undefined
error.
The following is my GoogleApi helper class:
public final class GoogleApi {
private static final Plus plus = GWT.create(Plus.class);
private final String clientId;
private final ClientOAuth2Login oAuth2Login;
private ClientGoogleApiRequestTransport requestTransport;
/**
* #param clientId
* This app's personal client ID assigned by the Google APIs
* Console (http://code.google.com/apis/console)
*/
public GoogleApi(EventBus eventBus, String clientId) {
this.clientId = clientId;
requestTransport = new ClientGoogleApiRequestTransport();
requestTransport.setApplicationName(MY_APP_NAME)
.setApiAccessKey(MY_API_KEY);
plus.initialize(eventBus, requestTransport);
oAuth2Login = new ClientOAuth2Login(clientId);
oAuth2Login.withScopes(PlusAuthScope.PLUS_ME);
}
public void login(final Receiver<String> callback) {
oAuth2Login.login(new Receiver<String>() {
#Override
public void onSuccess(String response) {
requestTransport.setAccessToken(response);
callback.onSuccess(response);
}
#Override
public void onFailure(ServerFailure error) {
Window.alert(error.getMessage());
}
});
}
public void getUserInfo(Receiver<Person> receiver) {
plus.people().get("me").to(receiver).fire();
}
}
The following shows where the failure occurs:
GoogleApi googleApi = new GoogleApi(eventBus, MY_CLIENT_ID);
googleApi.login(new Receiver<String>() {
#Override
public void onSuccess(final String token) {
// login is successful and access token is received
// but the following call fails with "Cannot call method 'newHttpRequest'
// of undefined" error
googleApi.getUserInfo(new Receiver<Person>() {
#Override
public void onSuccess(Person person) {
// never gets here
}
#Override
public void onFailure(ServerFailure error) {
// nor here
}
});
}
}
Try updating your gwt-google-apis libraries, there's been a change back in June that replaced calls to $wnd.googleapis.newHttpRequest() with calls to $wnd.gapi.client.rpcRequest(): https://code.google.com/p/gwt-google-apis/source/detail?r=2041
The reason authentication works it that it doesn't use the same code to talk to the server.
I have played around with the code (still using version 1.0.2-alpha) and made it work! The following is the updated code:
public final class GoogleApi {
private static final Plus plus = GWT.create(Plus.class);
private final String clientId;
private EventBus eventBus;
private final ClientOAuth2Login oAuth2Login;
private ClientGoogleApiRequestTransport requestTransport;
private String accessToken;
/**
* #param clientId
* This app's personal client ID assigned by the Google APIs
* Console (http://code.google.com/apis/console)
*/
public GoogleApi(final EventBus eventBus, String clientId) {
this.eventBus = eventBus;
this.clientId = clientId;
oAuth2Login = new ClientOAuth2Login(clientId);
oAuth2Login.withScopes(PlusAuthScope.PLUS_ME);
}
public void login(final Receiver<String> callback) {
oAuth2Login.login(new Receiver<String>() {
#Override
public void onSuccess(String response) {
accessToken = response;
callback.onSuccess(response);
}
#Override
public void onFailure(ServerFailure error) {
Window.alert(error.getMessage());
}
});
}
public void getUserInfo(final Receiver<Person> receiver) {
requestTransport = new ClientGoogleApiRequestTransport();
requestTransport.setApplicationName(ClientConstants.GOOGLE_APP_NAME)
.setApiAccessKey(ClientConstants.GOOGLE_API_KEY)
.setAccessToken(accessToken);
requestTransport.create(new Receiver<GoogleApiRequestTransport>() {
#Override
public void onSuccess(GoogleApiRequestTransport transport) {
plus.initialize(eventBus, transport);
plus.people().get("me").to(receiver).fire();
}
});
}
}
I don't know how efficient this is, though. A call to Plus's initialize() method is made every time a call to getUserInfo() is made.
Next step for me is to manually build a jar with the latest version of the API and adjust my code accordingly :/ Wish me luck!
Related
here is my problem:
i have used MVVM/Repository design pattern like this:
Activity -(Observes)-> ViewModel's LiveData -> Repository -> WebService API (GET Resource)
i have another calls for UPDATING Resource to WebService.
Problem:
after changing resource on the server. how i can make the Resource livedata to update itself with new servers data
i want to force it fetch data from server again because some other data may have been changed.
and i dont want to use local database (Room) and change it because my server data might be changed. and they need to fetch each time.
The Only solution passed my Mind was to create a Livedata Source (as dataVersion) to it.
and increment it after every update like this (pseudo code):
dataVersion = new MutableLiveData();
dataVersion.setValue(0);
// my repository get method hasnt anything to do with the dataVersion.
myData = Transformation.switchmap(dataVersion, versionNum -> { WebServiceRepo.getList() });
and how dataVersion should get updated in ViewModel.
You could extend MutableLiveData to give it manual fetch functionality.
public class RefreshLiveData<T> extends MutableLiveData<T> {
public interface RefreshAction<T> {
private interface Callback<T> {
void onDataLoaded(T t);
}
void loadData(Callback<T> callback);
}
private final RefreshAction<T> refreshAction;
private final Callback<T> callback = new RefreshAction.Callback<T>() {
#Override
public void onDataLoaded(T t) {
postValue(t);
}
};
public RefreshLiveData(RefreshAction<T> refreshAction) {
this.refreshAction = refreshAction;
}
public final void refresh() {
refreshAction.loadData(callback);
}
}
Then you can do
public class YourViewModel extends ViewModel {
private RefreshLiveData<List<Project>> refreshLiveData;
private final GithubRepository githubRepository;
private final SavedStateHandle savedStateHandle;
public YourViewModel(GithubRepository githubRepository, SavedStateHandle savedStateHandle) {
this.githubRepository = githubRepository;
this.savedStateHandle = savedStateHandle;
refreshLiveData = Transformations.switchMap(savedStateHandle.getLiveData("userId", ""), (userId) -> {
githubRepository.getProjectList(userId);
});
}
public void refreshData() {
refreshLiveData.refresh();
}
public LiveData<List<Project>> getProjects() {
return refreshLiveData;
}
}
And then repository can do:
public RefreshLiveData<List<Project>> getProjectList(String userId) {
final RefreshLiveData<List<Project>> liveData = new RefreshLiveData<>((callback) -> {
githubService.getProjectList(userId).enqueue(new Callback<List<Project>>() {
#Override
public void onResponse(Call<List<Project>> call, Response<List<Project>> response) {
callback.onDataLoaded(response.body());
}
#Override
public void onFailure(Call<List<Project>> call, Throwable t) {
}
});
});
return liveData;
}
I'm new to retrofit and i am trying te get a json response to an object called RootObject. The error that i am stuck with is :
"Error:(21, 44) error: incompatible types: NewsController cannot be
converted to Callback>"
Does someone now my mistake here? thanks in regards!
public class NewsController {
public void getNews(){
Retrofit retrofit = new Retrofit.Builder().baseUrl("apilink").addConverterFactory(GsonConverterFactory.create()).build();
GetNewsService service = retrofit.create(GetNewsService.class);
try {
service.GetNewsItems().enqueue(this); //asynchronous
Response<List<RootObject>> response = service.GetNewsItems().execute(); //synchronous
}
catch (IOException e){
}
}
}
class to put the data:
public class RootObject implements Serializable {
public ArrayList<Result> results ;
public int nextId;
public ArrayList<Result> getResults() { return results; }
public int getNextId() { return nextId; }
public String toString() {
return String.format("JEEJ" + nextId);
}
}
Interface:
public interface GetNewsService {
#GET("/Articles")
Call<List<RootObject>> GetNewsItems();
}
First of all,
change your interface to this:
public interface GetNewsService {
#GET("/Articles")
void GetNewsItems(Callback<List<RootObject>> cb);
}
Also change your newsController class.
public class NewsController {
private RestAdapter restAdapter;
static final String API_URL = "[Enter your API base url here]";
public void getNews(){
OkHttpClient mOkHttpClient = new OkHttpClient();
mOkHttpClient.setConnectTimeout(15000,TimeUnit.MILLISECONDS);
mOkHttpClient.setReadTimeout(15000,TimeUnit.MILLISECONDS);
restAdapter = new RestAdapter.Builder().setEndpoint(API_URL).setClient(new OkClient(mOkHttpClient)).setLogLevel(RestAdapter.LogLevel.FULL) .build();
GetNewsService service = restAdapter.create(GetNewsService.class);
Callback<List<RootObject> cb = new Callback<List<RootObject>>() {
#Override
public void success(List<RootObject> rootObjectList, Response response) {
//whatever you want to do with the fetched news items
}
#Override
public void failure(RetrofitError error) {
//whatever you want to do with the error
}
};
service.GetNewsItems(cb);
}
}
You'll need to add the following dependencies in your build.gradle:
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.google.code.gson:gson:2.3.1'
compile 'com.squareup.okhttp:okhttp:2.4.0'
#megh vidani's answer works, but he had you switch your code from Retrofit 2 to Retrofit 1. Here is how to do it in Retrofit 2. You would need to go back to your original gradle settings, etc. --
public class NewsController {
public void getNews(){
Retrofit retrofit = new Retrofit.Builder().baseUrl("apilink").addConverterFactory(GsonConverterFactory.create()).build();
GetNewsService service = retrofit.create(GetNewsService.class);
service.GetNewsItems().enqueue(new Callback<List<RootObject>>() {
#Override
public void onResponse(Response<List<RootObject>> response) {
// Handle your response
// Note HTTP errors are delivered here, you can check
// response.isSuccess() or response.code() to determine
// HTTP failures
}
#Override
public void onFailure(Throwable t) {
// Network errors
}
});
}
}
Im trying to determine when LoopJ has finished all background thread http calls. So that i can then display the results of an array that is populated based on the results of my onSuccess methods.
First off, I have a String[] of file names. I'm then looping through the array and creating loopj connections like such.
ArrayList<String> files_to_update = new ArrayList<String>(file_names.length);
AsyncHttpClient client = new AsyncHttpClient();
for (final String file_name : file_names) {
client.get(BASE_URL + file_name, new AsyncHttpResponseHandler() {
public void onStart() {
Local_Last_Modified_Date = preferences.getString(file_name, "");
}
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
Server_Last_Modified_Date = headers[3].getValue();
}
#Override
public void onFinish() {
if (!Local_Last_Modified_Date.trim().equalsIgnoreCase(Server_Last_Modified_Date.trim())) {
files_to_update.add(file_name);
}
}
});
}
What i'm doing here is comparing 2 date strings, The first Local_Last_Modified_Date is pulled from a preference file and the 2nd is determined by the last-modified date in the header. and then compared in the OnFinish(). This determines if the file needs to be update because the server file is newer than the preference date. Now! i know this is not the best way for comparing dates, however it will work interm for what i'm trying to do.
The issue i'm having is determining that all of the background http calls from loopj have completed so that i can now display the results of array list in a list dialog or whatever ui element i choose. I've tried looping through the arraylist, but because the loopj / http connections are background threads, the loop gets executed prior to the completion of all of the connection and therefore displays an empty or not populated fully array.
Is there a if conditional that i can write to determine if loopj has not finished executing all of the connection and when it has then execute my ui code?
The following code should address your problem:
Class file: UploadRunner.java
public class UploadRunner extends AsyncHttpResponseHandler implements Runnable {
private final AsyncHttpClient client;
private final ArrayList<String> filesList;
private final int filesCount;
private final Handler handler;
private String baseURI;
private boolean isFired;
private int filesCounter;
// Use in case you have no AHC ready beforehand.
public UploadRunner(ArrayList<String> filesList) {
this(new AsyncHttpClient(), filesList);
}
public UploadRunner(
AsyncHttpClient client,
ArrayList<String> filesList,
Handler handler
) {
assert null != client;
assert null != filesList;
assert null != handler;
this.client = client;
this.filesList = filesList;
this.handler = handler;
this.baseURI = "";
this.filesCount = filesList.size();
this.filesCounter = 0;
}
public String getBaseURI() {
return baseURI;
}
public void setBaseURI(String uri) {
baseURI = uri;
}
#Override
public void run() {
// Request to download all files.
for(final String file : filesList) {
client.get(baseURI + file, this);
}
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// This shouldn't happen really...
if(isFired) {
return;
}
// One more file downloaded.
filesCounter++;
// If all files downloaded, fire the callback.
if(filesCounter >= filesCount) {
isFired = true;
handler.onFinish(getLastModificationDate(headers));
}
}
private String getLastModificationDate(Header[] headers) {
// Simple mechanism to get the date, but maybe a proper one
// should be implemented.
return headers[3].getValue();
}
public static interface Handler {
public void onFinish(String lastModificationDate);
// TODO: Add onError() maybe?
}
}
In this case, you encapsulate the uploading mechanism in one place, plus expose just an interface for calling back a handler when all files are uploaded.
Typical use case:
// TODO: This typically should run in a different thread.
public class MyTask implements UploadRunner.Handler, Runnable {
private final static BASE_URI = "http://www.example.com/";
private final AsyncHttpClient client = new AsyncHttpClient();
private final ArrayList<String> filesList = new ArrayList<>();
#Override
public void run() {
filesList.add("1.png");
filesList.add("2.png");
filesList.add("3.png");
filesList.add("4.png");
filesList.add("5.png");
// Create a new runner.
UploadRunner ur = new UploadRunner(client, filesList, this);
// Set base URI.
ur.setBaseURI(BASE_URI);
// Spring the runner to life.
ur.run();
}
#Override
public void onFinish(String lastModificationDate) {
// All files downloaded, and last modification date is supplied to us.
}
}
For a specific controller action I want to turn off cookies. I've tried to remove the cookie Map, but that doesn't seem to work. I need to completely remove all response headers except my own.
Any ideas?
I found this solution when Googling this problem. It does the same thinng you try, removing cookies map, but it is done in an method which is annotated with #Finally.
I believe cookies map is filled after render() but before any #Finally annotated class.
Credits to Alex Jarvis on Google Groups, code is copied for reference:
/**
* Removes cookies from all responses.
*
* This is because cookies are not required in stateless webservice and
* we don't want to send any unnecessary information to the client.
*
* #author Alex Jarvis
*/
public class NoCookieFilter extends Controller {
/** An empty cookie map to replace any cookies in the response. */
private static final Map<String, Http.Cookie> cookies = new HashMap<String, Http.Cookie>(0);
/**
* When the configuration property 'cookies.enabled' equals false,
* this Finally filter will replace the cookies in the response with an empty Map.
*/
#Finally
protected static void removeCookies() {
boolean cookiesEnabled = Boolean.parseBoolean(Play.configuration.getProperty("cookies.enabled"));
if (!cookiesEnabled) {
response.cookies = cookies;
}
}
}
Usage: For any controller you want to be "cookieless" annotate it with
#With(NoCookieFilter.class)
(Tested in Play 1.2.5)
I managed to wrap the response with a wrapper with response.current.set(new CookieLessResponseWrapper(response.current())). Works ok for me.
Here is the code for the Response wrapper if anyone is interested.
package helpers;
import play.mvc.Http.Response;
public class CookieLessResponseWrapper extends Response {
private Response wrappedResponse;
public CookieLessResponseWrapper(Response response) {
this.wrappedResponse = response;
}
#Override
public void accessControl(String allowOrigin, boolean allowCredentials) {
wrappedResponse.accessControl(allowOrigin, allowCredentials);
}
#Override
public void accessControl(String allowOrigin, String allowMethods,
boolean allowCredentials) {
wrappedResponse.accessControl(allowOrigin, allowMethods, allowCredentials);
}
#Override
public void accessControl(String allowOrigin) {
wrappedResponse.accessControl(allowOrigin);
}
#Override
public void cacheFor(String etag, String duration, long lastModified) {
wrappedResponse.cacheFor(etag, duration, lastModified);
}
#Override
public void cacheFor(String duration) {
wrappedResponse.cacheFor(duration);
}
#Override
public String getHeader(String name) {
return wrappedResponse.getHeader(name);
}
#Override
public void print(Object o) {
wrappedResponse.print(o);
}
#Override
public void removeCookie(String name) {
wrappedResponse.removeCookie(name);
}
#Override
public void reset() {
wrappedResponse.reset();
}
#Override
public void setContentTypeIfNotSet(String contentType) {
wrappedResponse.setContentTypeIfNotSet(contentType);
}
#Override
public void setCookie(String name, String value, String domain,
String path, Integer maxAge, boolean secure, boolean httpOnly) {
}
#Override
public void setCookie(String name, String value, String domain,
String path, Integer maxAge, boolean secure) {
}
#Override
public void setCookie(String name, String value, String duration) {
}
#Override
public void setCookie(String name, String value) {
}
#Override
public void setHeader(String name, String value) {
wrappedResponse.setHeader(name, value);
}
}
You should be able to clear all headers, in your action, with:
Http.Response.current().reset();
Have in mind that the Session is a Cookie. I don't believe that you can remove it.
How about use discarding the whole session for each request as a workaround?
Discarding the whole session
Ok("Bye").withNewSession
https://www.playframework.com/documentation/2.3.x/ScalaSessionFlash#Discarding-the-whole-session
What's the best way to achieve Rails-like flash messages such as "Update successful" http://api.rubyonrails.org/classes/ActionController/Flash.html) in the Java world? I'm using Spring MVC.
I have done just that in Spring MVC with a session scoped bean.
public class FlashImpl implements Flash, Serializable{
private static final long serialVersionUID = 1L;
private static final String ERROR = "error";
private static final String WARNING = "warning";
private static final String NOTICE = "notice";
private String message;
private String klass;
public void message(String klass, String message) {
this.klass = klass;
this.message = message;
}
public void notice(String message) {
this.message(NOTICE, message);
}
public void warning(String message) {
this.message(WARNING, message);
}
public void error(String message) {
this.message(ERROR, message);
}
public boolean isEmptyMessage() {
return message == null;
}
public void clear() {
this.message = null;
this.klass = null;
}
public String getMessage() {
String msg = message;
this.clear();
return msg;
}
public void setMessage(String message) {
this.message = message;
}
public String getKlass() {
return klass;
}
public void setKlass(String klass) {
this.klass = klass;
}}
The trick is in consumming the message once it's been read for the first time. This way it can survive to a redirect after post.
I am assuming that there will be only one type of message for request!. If you don't want this you could create a hashmap as already suggested.
I inject this bean in my controllers (actually I inject it in a base controller inherited by all the others).
In your JSP you have to add some code like this:
<c:if test="${!flash.emptyMessage}" >
<div class="${flash.klass}">${fn:escapeXml(flash.message)}</div>
</c:if>
I would recommend implementing this as a session-wide HashTable, with string keys mapping to custom FlashItem objects. The FlashItem will simply contain the object or string you're storing plus a boolean value, possibly called IsNew, which should be set to true when you insert a new item into the HashTable.
On each page load you then iterate the HashTable, set any IsNew = true items to false, and delete any items where IsNew is already false. That should give you a work-alike to Rails's flash feature.
This has been added to Spring MVC 3.1.RC1:
3.1.15 Flash Attributes and RedirectAttributes
Flash attributes can now be stored in a FlashMap and saved in the HTTP session to survive a redirect. For an overview of the general support for flash attributes in Spring MVC see Section 16.6, “Using flash attributes”.
In annotated controllers, an #RequestMapping method can add flash attributes by declaring a method argument of type RedirectAttributes. This method argument can now also be used to get precise control over the attributes used in a redirect scenario. See Section 16.3.3.10, “Specifying redirect and flash attributes” for more details.
(JIRA issue: SPR-6464)
I've used Manolo Santos' example with with Spring MVC as follows:
Annotate the Flash class with #Component, and add a boolean variable to indicate if the message should live for one more request.
#Component
public class Flash {
private static final String INFO = "info";
private static final String SUCCESS = "success";
private static final String ERROR = "error";
private static final String WARNING = "warning";
private static final String NOTICE = "notice";
private final Map msgs = new HashMap();
private boolean isKept; // keep msg for one more request (when the controller method redirects to another)
private void message(String severity, String message) {
msgs.put(message, severity);
}
public void info(String message) {
this.message(INFO, message);
}
public void success(String message) {
this.message(SUCCESS, message);
}
public void notice(String message) {
this.message(NOTICE, message);
}
public void warning(String message) {
this.message(WARNING, message);
}
public void error(String message) {
this.message(ERROR, message);
}
public boolean isEmptyMessage() {
return msgs.isEmpty();
}
public void clear() {
msgs.clear();
isKept = false;
}
public Map getMessage() {
return msgs;
}
public boolean isKept() {
return isKept;
}
public void keep() {
isKept = true;
}
public void unKeep() {
isKept = false;
}
}
Use an interceptor to add the flash message to the model object.
public class FlashMessageInterceptor extends HandlerInterceptorAdapter {
#Resource
Flash flash;
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if (!flash.isKept()) {
modelAndView.addObject("flash", flash);
}
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if (flash.isKept()) {
flash.unKeep();
}
else {
flash.clear();
}
}
}
In your controller, if you have a method that redirects to another method you could just say; flush.keep(), to have the flash message displayed.
#Controller
public class ComputerCampLove {
#Resource
private Flash flash;
#RequestMapping(method = RequestMethod.GET)
public String takeMeToAnotherPlace(Model model) {
flash.info("Fa-fa-fa!");
flash.keep();
return "redirect:somewhere";
}
}
If you have not invested a huge amount of work into your spring java app, you could look at running rails on jruby. The beauty of running jRuby on Rails is that you can mix and match ruby gems and java libs.
If you have already put a fair amount of work into your application then this is more then likely not an option.