Skip to content

Commit

Permalink
switched login to RestTemplate (XML) + GreenRobot EventBus, refs arte…
Browse files Browse the repository at this point in the history
  • Loading branch information
ilya-murzinov committed Dec 29, 2014
1 parent 379042f commit 22227fc
Show file tree
Hide file tree
Showing 19 changed files with 525 additions and 173 deletions.
20 changes: 20 additions & 0 deletions wail-app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,19 @@ android {

packagingOptions {
exclude 'META-INF/services/javax.annotation.processing.Processor'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/ASL2.0'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}

dexOptions {
preDexLibraries = false
}

lintOptions {
disable 'InvalidPackage'
}
Expand Down Expand Up @@ -69,6 +81,14 @@ dependencies {
compile 'com.melnykov:floatingactionbutton:1.1.0'
compile 'com.rengwuxian.materialedittext:library:1.7.1'
compile 'com.jakewharton:butterknife:5.1.2'
compile 'com.path:android-priority-jobqueue:1.1.2'
compile 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE'
compile 'de.greenrobot:eventbus:2.4.0'
compile('org.simpleframework:simple-xml:2.7') {
exclude module: 'stax'
exclude module: 'stax-api'
exclude module: 'xpp3'
}

compile fileTree(dir: 'libs', include: '*.jar')
}
Expand Down
4 changes: 4 additions & 0 deletions wail-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
android:name="com.google.analytics.tracking.android.CampaignTrackingService"
android:enabled="true" />

<service
android:name=".service.JobManagerService"
android:exported="false" />

<receiver
android:name="com.google.analytics.tracking.android.CampaignTrackingReceiver"
android:exported="true"
Expand Down
6 changes: 6 additions & 0 deletions wail-app/src/main/java/com/artemzin/android/wail/WAILApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import android.os.AsyncTask;
import android.os.SystemClock;

import com.artemzin.android.wail.service.JobManagerService;
import com.artemzin.android.wail.service.LastFmEventHandler;
import com.artemzin.android.wail.service.WAILService;
import com.artemzin.android.wail.storage.WAILSettings;
import com.artemzin.android.wail.storage.db.PlayersDBHelper;
Expand All @@ -16,13 +18,17 @@
import com.google.analytics.tracking.android.EasyTracker;
import com.google.analytics.tracking.android.MapBuilder;

import de.greenrobot.event.EventBus;

public class WAILApp extends Application {

@Override
public void onCreate() {
LocaleUtil.updateLanguage(this, null);
super.onCreate();
Loggi.w("WAILApp onCreate()");
startService(new Intent(getApplicationContext(), JobManagerService.class));
EventBus.getDefault().register(new LastFmEventHandler());
updateSupportedPlayersDB();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ public class MD5Hash {
* Result should be equals to PHP md5() function
* @param input string md5 from which should be calculated
* @return calculated md5 hash from input string
* @throws NoSuchAlgorithmException if md5 could not be calculated, because algorithm not founded
*/
public static String calculateMD5(String input) throws NoSuchAlgorithmException {
public static String calculateMD5(String input) {
try {
final byte[] bytes = digest.digest(input.getBytes("UTF-8"));
final StringBuilder b = new StringBuilder(32);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.artemzin.android.wail.api.lastfm;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.xml.SimpleXmlHttpMessageConverter;
import org.springframework.util.MultiValueMap;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* @author Ilya Murzinov [murz42@gmail.com]
*/
class CustomMessageConverter implements HttpMessageConverter<Object> {
private HttpMessageConverter<Object> inputConverter;
private HttpMessageConverter<MultiValueMap<String, ?>> outputConverter;

CustomMessageConverter() {
inputConverter = new SimpleXmlHttpMessageConverter();
outputConverter = new FormHttpMessageConverter();
}

@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return inputConverter.canRead(clazz, mediaType);
}

@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return outputConverter.canWrite(clazz, mediaType);
}

@Override
public List<MediaType> getSupportedMediaTypes() {
List<MediaType> supportedMediaTypes = new ArrayList<>(inputConverter.getSupportedMediaTypes());
supportedMediaTypes.addAll(outputConverter.getSupportedMediaTypes());
return supportedMediaTypes;
}

@Override
public Object read(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return inputConverter.read(clazz, inputMessage);
}

@Override
@SuppressWarnings("unchecked")
public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
if (!(o instanceof MultiValueMap)) {
throw new HttpMessageNotWritableException("Can't write object " + o);
}
outputConverter.write((MultiValueMap<String, ?>) o, contentType, outputMessage);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package com.artemzin.android.wail.api.lastfm;

import com.artemzin.android.wail.api.MD5Hash;
import com.artemzin.android.wail.api.lastfm.model.LastFmSession;
import com.artemzin.android.wail.events.InvalidUsernamePasswordEvent;
import com.artemzin.android.wail.events.NetworkErrorEvent;
import com.artemzin.android.wail.events.ServiceUnavailableEvent;
import com.artemzin.android.wail.events.UnknownLoginErrorEvent;
import com.artemzin.android.wail.storage.WAILSettings;

import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.xml.SimpleXmlHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import de.greenrobot.event.EventBus;

/**
* @author Ilya Murzinov
*/
public class LastFmClient {
public static final String API_ROOT_URL = "https://ws.audioscrobbler.com/2.0/";

public static final String PARAM_API_KEY = "api_key";
public static final String PARAM_API_SIG = "api_sig";
public static final String PARAM_SK = "sk";

public static final int INVALID_USERNAME_PASSWORD = 4;
public static final int SERVICE_UNAVAILABLE = 11;

private final RestTemplate restTemplate;

public LastFmClient() {
restTemplate = new RestTemplate();

restTemplate.setMessageConverters(
Collections.<HttpMessageConverter<?>>singletonList(new CustomMessageConverter())
);
restTemplate.setInterceptors(Collections.<ClientHttpRequestInterceptor>singletonList(new ClientHttpRequestInterceptor() {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
return execution.execute(request, body);
}
}));
restTemplate.setErrorHandler(new LastFmResponseErrorHandler());
}

public LastFmSession authenticate(String username, String password) {
MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
request.add("method", "auth.getMobileSession");
request.add("username", username);
request.add("password", password);
try {
return restTemplate.postForObject(
API_ROOT_URL,
generateSignedRequest(request),
LastFmSession.class
);
} catch (RestClientException e) {
EventBus.getDefault().post(new NetworkErrorEvent());
throw e;
}
}

private MultiValueMap<String, String> generateSignedRequest(MultiValueMap<String, String> request) {
MultiValueMap<String, String> result = new LinkedMultiValueMap<>(request);

result.add(PARAM_API_KEY, WAILSettings.getLastfmApiKey());

StringBuilder stringBuilder = new StringBuilder();
List<Map.Entry<String, List<String>>> entrySet = new ArrayList<>(result.entrySet());
Collections.sort(entrySet, new Comparator<Map.Entry<String, List<String>>>() {
@Override
public int compare(Map.Entry<String, List<String>> lhs, Map.Entry<String, List<String>> rhs) {
return String.CASE_INSENSITIVE_ORDER.compare(lhs.getKey(), rhs.getKey());
}
});
for (Map.Entry<String, List<String>> entry : entrySet) {
stringBuilder.append(entry.getKey()).append(entry.getValue().get(0));
}
stringBuilder.append(WAILSettings.getLastfmSecret());
result.add(PARAM_API_SIG, MD5Hash.calculateMD5(stringBuilder.toString()));
return result;
}

private static class LastFmResponseErrorHandler implements ResponseErrorHandler {
private ErrorResponse errorResponse;

@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
if (response.getStatusCode() != HttpStatus.OK) {
errorResponse = (ErrorResponse) new SimpleXmlHttpMessageConverter().read(ErrorResponse.class, response);
return true;
}
return false;
}

@Override
public void handleError(ClientHttpResponse response) throws IOException {
if (errorResponse.getError().getCode() == INVALID_USERNAME_PASSWORD) {
EventBus.getDefault().post(new InvalidUsernamePasswordEvent());
} else if (errorResponse.getError().getCode() == SERVICE_UNAVAILABLE) {
EventBus.getDefault().post(new ServiceUnavailableEvent());
} else {
EventBus.getDefault().post(new UnknownLoginErrorEvent());
}
throw new RuntimeException();
}
}

@Root(name = "lfm", strict = false)
private static class ErrorResponse {
@Element(name = "error")
private Error error;

public Error getError() {
return error;
}

public void setError(Error error) {
this.error = error;
}

public static class Error {
@Attribute(name = "code")
private int code;

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.artemzin.android.wail.api.lastfm.model;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

/**
* @author Ilya Murzinov [murz42@gmail.com]
*/
@Root(name = "lfm", strict = false)
public class LastFmSession {
@Element(name = "session", required = true)
private Session session;

public Session getSession() {
return session;
}

public void setSession(Session session) {
this.session = session;
}

public static class Session {
private String name;
private String key;
private String subscriber;

public String getName() {
return name;
}

public String getKey() {
return key;
}

public String getSubscriber() {
return subscriber;
}
}
}
Loading

0 comments on commit 22227fc

Please sign in to comment.