/* * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Codename One designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Codename One through http://www.codenameone.com/ if you * need additional information or have any questions. */ package com.codename1.social; import com.codename1.io.AccessToken; import com.codename1.io.Log; import com.codename1.io.Oauth2; import com.codename1.io.Preferences; import com.codename1.io.Util; import com.codename1.ui.Display; import com.codename1.ui.events.ActionEvent; import com.codename1.ui.events.ActionListener; import java.io.IOException; /** * The Login abstract base class is used to simplify Oauth2 authentications * services. * Services can override the default Oauth2 web login and offers the native login * experience. * * @author Chen */ public abstract class Login { LoginCallback callback = new LoginCallBackProxy(); private LoginCallback loginCallback; private boolean callbackEnabled = true; private String validateErr = null; private AccessToken token; String oauth2URL; String clientId; String redirectURI; String clientSecret; String scope; /** * Logs in the user. * If the service has a native login it will try to use that, otherwise an * Oauth2 web login will be used. */ public void doLogin(){ if (isNativeLoginSupported()) { nativelogin(); } else { if (oauth2URL == null) { System.out.println("No oauth2URL found Use setOauth2URL"); return; } if (clientId == null) { System.out.println("No ClientId found Use setClientId"); return; } if (redirectURI == null) { System.out.println("No redirectURI found Use setRedirectURI"); return; } if (clientSecret == null) { System.out.println("No clientSecret found Use setClientSecret"); return; } Oauth2 auth = createOauth2(); auth.showAuthentication(new ActionListener() { public void actionPerformed(ActionEvent evt) { //success if (evt.getSource() instanceof AccessToken) { AccessToken t = (AccessToken)evt.getSource(); setAccessToken(t); if(callback != null){ callback.loginSuccessful(); } return; } if (evt.getSource() instanceof String) { String t = (String)evt.getSource(); setAccessToken(new AccessToken(t, null)); if(callback != null){ callback.loginSuccessful(); } return; } if (evt.getSource() instanceof Exception) { if(callback != null){ Exception e = (Exception) evt.getSource(); Log.e(e); callback.loginFailed(e.getMessage()); } } } }); } } /** * Logs out the current user */ public void doLogout(){ if (isNativeLoginSupported()) { nativeLogout(); } else { setAccessToken(null); } Preferences.delete(Login.this.getClass().getName() + "Token"); } /** * Indicates if the user is currently logged in * * @return true if logged in */ public boolean isUserLoggedIn() { if (isNativeLoginSupported()) { return nativeIsLoggedIn(); } else { return token != null; } } /** * Indicates if the user is currently logged in. * Subclasses that uses a native sdk to login/logout should override this * method. * * @return true if logged in */ public boolean nativeIsLoggedIn(){ throw new RuntimeException("Native isLoggedIn not implemented"); } /** * Logs in the current user natively. * Subclasses that uses a native sdk to login/logout should override this * method. */ public void nativelogin(){ throw new RuntimeException("Native login not implemented"); } /** * Logs out the current user natively. * Subclasses that uses a native sdk to login/logout should override this * method. */ public void nativeLogout(){ throw new RuntimeException("Native logout not implemented"); } /** * Returns true if this service supports native login. * If implementation returns true here, the nativelogin, nativelogout, * nativeIsLoggedIn should be implemented * * @return true if the service supports native login */ public abstract boolean isNativeLoginSupported(); /** * The AccessToken of this service * * @return the token */ public AccessToken getAccessToken() { return token; } /** * This method tries to validate the last access token if exists, if the * last token is not valid anymore it will try to login the user in order to * get a fresh token * The method blocks until a valid token has been granted */ public void validateToken() throws IOException{ String token = Preferences.get(Login.this.getClass().getName() + "Token", null); if(token == null){ throw new RuntimeException("No token to validate"); } if(!validateToken(token)){ callbackEnabled = false; doLogin(); Display.getInstance().invokeAndBlock(new Runnable() { public void run() { while(!callbackEnabled){ Util.sleep(100); } } }); if(validateErr != null){ throw new IOException(validateErr); } } } /** * Returns true if the previous granted access token is still valid otherwise * false. * * @param token the access token to check * @return true of the token is valid */ protected abstract boolean validateToken(String token); /** * Sets the Login access token */ public void setAccessToken(AccessToken token) { this.token = token; } /** * Sets the login callback that will receive event callback notification * from the API * * @param lc the login callback or null to remove the existing login * callback */ public void setCallback(LoginCallback lc) { loginCallback = lc; } /** * The client id (appid) which asks to connect * * @param clientId */ public void setClientId(String id) { clientId = id; } /** * The client secret * * @param clientSecret */ public void setClientSecret(String secret) { clientSecret = secret; } /** * The redirect URI * * @param redirectURI */ public void setRedirectURI(String URI) { redirectURI = URI; } /** * The authentication scope */ public void setScope(String scope) { this.scope = scope; } /** * The oauth2 URL */ public void setOauth2URL(String oauth2URL) { this.oauth2URL = oauth2URL; } /** * Creates the oauth2 to be used to login in case no native login is available * for this service. * * @return the Oauth2 to be used to login if no native login available and * on the simulator */ protected Oauth2 createOauth2() { Oauth2 auth = new Oauth2(oauth2URL, clientId, redirectURI, scope); return auth; } class LoginCallBackProxy extends LoginCallback{ public void loginSuccessful() { //store the access token upon login success for future use Preferences.set(Login.this.getClass().getName() + "Token", getAccessToken().getToken()); if(callbackEnabled){ if(loginCallback != null){ loginCallback.loginSuccessful(); } return; } callbackEnabled = true; validateErr = null; } public void loginFailed(String errorMessage) { if(callbackEnabled){ if(loginCallback != null){ loginCallback.loginFailed(errorMessage); } return; } callbackEnabled = true; validateErr = errorMessage; } } }