package org.jboss.aerogear.android.impl.simplepush;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.util.Pair;
import static com.google.android.gms.cast.CastStatusCodes.TIMEOUT;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jboss.aerogear.android.Callback;
import org.jboss.aerogear.android.Provider;
import org.jboss.aerogear.android.http.HttpException;
import org.jboss.aerogear.android.impl.http.HttpRestProviderForPush;
import org.jboss.aerogear.android.impl.util.UrlUtils;
import org.jboss.aerogear.android.unifiedpush.PushConfig;
import org.jboss.aerogear.android.unifiedpush.PushRegistrar;
public class AeroGearSimplePushRegistrar implements PushRegistrar {
private final SimplePushConfig config;
private SimplePushService service;
private static final String registryDeviceEndpoint = "/rest/registry/device";
private static final String TAG = AeroGearSimplePushRegistrar.class.toString();
private Provider<HttpRestProviderForPush> httpProviderProvider = new Provider<HttpRestProviderForPush>() {
@Override
public HttpRestProviderForPush get(Object... in) {
return new HttpRestProviderForPush((URL) in[0], (Integer) in[1]);
}
};
public AeroGearSimplePushRegistrar(SimplePushConfig config) {
this.config = config;
}
@Override
public void register(final Context context, final Callback<Void> callback) {
final Looper callerLooper = Looper.myLooper();
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
synchronized (AeroGearSimplePushRegistrar.class) {
if (service == null) {
Log.d("test", "Service is null.");
context.startService(new Intent(context, SimplePushService.class));
context.bindService(new Intent(context, SimplePushService.class), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
Log.d("test", "Service connected.");
SimplePushService.SimplePushBinder binder = (SimplePushService.SimplePushBinder) iBinder;
AeroGearSimplePushRegistrar.this.service = binder.getService();
List<Pair<String, Future<PushChannel>>> categoryEndpoints = new ArrayList<Pair<String, Future<PushChannel>>>();
for (String category : config.getCategories()) {
Log.d("test", "Registering cat " + category);
Future<PushChannel> channel;
try {
channel = service.register(category);
} catch (final Exception ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
}
Log.d("test", "In process cat " + category);
categoryEndpoints.add(Pair.create(category, channel));
}
for (Pair<String, Future<PushChannel>> categoryEndpoint : categoryEndpoints) {
URL deviceRegistryURL;
try {
deviceRegistryURL = UrlUtils.appendToBaseURL(config.getPushServerURI().toURL(), registryDeviceEndpoint);
Log.d("test", "URL " + deviceRegistryURL.toString());
} catch (final MalformedURLException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
}
HttpRestProviderForPush httpProvider = httpProviderProvider.get(deviceRegistryURL, TIMEOUT);
httpProvider.setPasswordAuthentication(config.getVariantID(), config.getSecret());
Gson gson = new GsonBuilder().setExclusionStrategies(
new ExclusionStrategy() {
private final ImmutableSet<String> fields;
{
fields = ImmutableSet.<String>builder()
.add("deviceToken")
.add("deviceType")
.add("alias")
.add("operatingSystem")
.add("osVersion")
.add("categories")
.build();
}
@Override
public boolean shouldSkipField(FieldAttributes f) {
return !(f.getDeclaringClass() == PushConfig.class && fields
.contains(f.getName()));
}
@Override
public boolean shouldSkipClass(Class<?> arg0) {
return false;
}
}).create();
try {
PushChannel categoryEndpointResult = categoryEndpoint.second.get(12000, TimeUnit.SECONDS);
Log.d("test", "URL " + deviceRegistryURL.toString());
config.setDeviceToken(categoryEndpointResult.getChannelId());
config.setSimplePushEndpoint(categoryEndpointResult.getEndpoint().toString());
config.setCategories(Lists.newArrayList(categoryEndpoint.first));
httpProvider.post(gson.toJson(config));
} catch (final HttpException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
} catch (final InterruptedException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
} catch (final ExecutionException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
} catch (final TimeoutException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
}
}
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onSuccess(null);
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
}, Context.BIND_AUTO_CREATE);
} else {
List<Pair<String, Future<PushChannel>>> categoryEndpoints = new ArrayList<Pair<String, Future<PushChannel>>>();
for (String category : config.getCategories()) {
Future<PushChannel> channel;
try {
channel = service.register(category);
} catch (final Exception ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
}
categoryEndpoints.add(Pair.create(category, channel));
}
for (Pair<String, Future<PushChannel>> categoryEndpoint : categoryEndpoints) {
URL deviceRegistryURL;
try {
deviceRegistryURL = UrlUtils.appendToBaseURL(config.getPushServerURI().toURL(), registryDeviceEndpoint);
} catch (final MalformedURLException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
}
HttpRestProviderForPush httpProvider = httpProviderProvider.get(deviceRegistryURL, TIMEOUT);
httpProvider.setPasswordAuthentication(config.getVariantID(), config.getSecret());
Gson gson = new GsonBuilder().setExclusionStrategies(
new ExclusionStrategy() {
private final ImmutableSet<String> fields;
{
fields = ImmutableSet.<String>builder()
.add("deviceToken")
.add("deviceType")
.add("alias")
.add("operatingSystem")
.add("osVersion")
.add("categories")
.build();
}
@Override
public boolean shouldSkipField(FieldAttributes f) {
return !(f.getDeclaringClass() == PushConfig.class && fields
.contains(f.getName()));
}
@Override
public boolean shouldSkipClass(Class<?> arg0) {
return false;
}
}).create();
try {
PushChannel categoryEndpointResult = categoryEndpoint.second.get(12000, TimeUnit.SECONDS);
config.setDeviceToken(categoryEndpointResult.getChannelId());
config.setSimplePushEndpoint(categoryEndpointResult.getEndpoint().toString());
config.setCategories(Lists.newArrayList(categoryEndpoint.first));
httpProvider.post(gson.toJson(config));
} catch (final HttpException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
} catch (final InterruptedException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
} catch (final ExecutionException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
} catch (final TimeoutException ex) {
Log.e(TAG, ex.getMessage(), ex);
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onFailure(ex);
}
});
return;
}
}
new Handler(callerLooper).post(new Runnable() {
@Override
public void run() {
callback.onSuccess(null);
}
});
}
}
}
});
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void unregister(Context context, Callback<Void> callback) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}