/** * */ package com.rackspacecloud.android; import java.util.ArrayList; import java.util.Collections; import org.apache.http.HttpResponse; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.util.TypedValue; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import com.rackspace.cloud.android.R; import com.rackspace.cloud.loadbalancer.api.client.LoadBalancer; import com.rackspace.cloud.loadbalancer.api.client.LoadBalancerManager; import com.rackspace.cloud.loadbalancer.api.client.Node; import com.rackspace.cloud.loadbalancer.api.client.VirtualIp; import com.rackspace.cloud.loadbalancer.api.client.http.LoadBalancersException; import com.rackspace.cloud.servers.api.client.CloudServersException; import com.rackspace.cloud.servers.api.client.http.HttpBundle; public class ViewLoadBalancerActivity extends CloudActivity { private final int EDIT_LOAD_BALANCER_CODE = 184; private final int EDIT_NODES_CODE = 185; private final int EDIT_THROTTLE_CODE = 186; private final int EDIT_ACCESS_CONTROL_CODE = 187; private final String DELETED = "DELETED"; private LoadBalancer loadBalancer; private PollLoadBalancerTask pollLoadBalancerTask; private AndroidCloudApplication app; private LoggingListenerTask loggingListenerTask; private SessionPersistenceListenerTask sessionPersistenceListenerTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); trackPageView(GoogleAnalytics.PAGE_LOADBALANCER); loadBalancer = (LoadBalancer) this.getIntent().getExtras().get("loadBalancer"); setContentView(R.layout.view_loadbalancer); app = (AndroidCloudApplication)this.getApplication(); restoreState(savedInstanceState); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("loadBalancer", loadBalancer); } protected void restoreState(Bundle state) { super.restoreState(state); if (state != null && state.containsKey("loadBalancer") && state.getSerializable("loadBalancer") != null) { loadBalancer = (LoadBalancer) state.getSerializable("loadBalancer"); loadLoadBalancerData(); setUpButtons(); } else{ new LoadLoadBalancerTask().execute((Void[]) null); } /* * if is setting logs we need another listener */ if(app.isSettingLogs()){ loggingListenerTask = new LoggingListenerTask(); loggingListenerTask.execute(); } if(app.isSettingSessionPersistence()){ sessionPersistenceListenerTask = new SessionPersistenceListenerTask(); sessionPersistenceListenerTask.execute(); } } @Override protected void onDestroy(){ super.onDestroy(); //need to cancel pollLoadBalancerTask so it //does not keep polling in a new activity if(pollLoadBalancerTask != null){ pollLoadBalancerTask.cancel(true); } } @Override protected void onStop(){ super.onStop(); /* * Need to stop running listener task * if we exit */ if(loggingListenerTask != null){ loggingListenerTask.cancel(true); } if(sessionPersistenceListenerTask != null){ sessionPersistenceListenerTask.cancel(true); } } private void setupButton(int resourceId, OnClickListener onClickListener) { Button button = (Button) findViewById(resourceId); button.setOnClickListener(onClickListener); } //change the text on the button depending //on the state of Connection Logging private void setLogButtonText(){ Button logs = (Button)findViewById(R.id.connection_log_button); String loggingEnabled = loadBalancer.getIsConnectionLoggingEnabled(); if(loggingEnabled != null && loggingEnabled.equals("true")){ logs.setText("Disable Logs"); } else { logs.setText("Enable Logs"); } } //change the text on the button depending //on the state of Session Persistence private void setSessionButtonText(){ Button sessionPersistence = (Button)findViewById(R.id.session_persistence_button); //session persistence is null if it is off if(loadBalancer.getSessionPersistence() != null){ sessionPersistence.setText("Disable Session Persistence"); } else { sessionPersistence.setText("Enable Session Persistence"); } } //if the load balancer state contains DELETE //then parts of it may be null, so use a different //onClick in that condition private void setUpButtons(){ if(loadBalancer != null){ setupButton(R.id.edit_loadbalancer_button, new OnClickListener() { @Override public void onClick(View v) { if(!loadBalancer.getStatus().contains(DELETED)){ Intent editLoadBalancerIntent = new Intent(getContext(), EditLoadBalancerActivity.class); editLoadBalancerIntent.putExtra("loadBalancer", loadBalancer); startActivityForResult(editLoadBalancerIntent, EDIT_LOAD_BALANCER_CODE); } else { showAlert(loadBalancer.getStatus(), "The load balancer cannot be updated."); } } }); setupButton(R.id.delete_loadbalancer_button, new OnClickListener() { @Override public void onClick(View v) { if(!loadBalancer.getStatus().contains(DELETED)){ showDialog(R.id.view_server_delete_button); } else { showAlert(loadBalancer.getStatus(), "The load balancer cannot be deleted."); } } }); setupButton(R.id.edit_nodes_button, new OnClickListener() { @Override public void onClick(View v) { if(!loadBalancer.getStatus().contains(DELETED)){ Intent editLoadBalancerIntent = new Intent(getContext(), EditNodesActivity.class); editLoadBalancerIntent.putExtra("nodes", loadBalancer.getNodes()); editLoadBalancerIntent.putExtra("loadBalancer", loadBalancer); startActivityForResult(editLoadBalancerIntent, EDIT_NODES_CODE); } else { showAlert(loadBalancer.getStatus(), "The nodes cannot be edited."); } } }); setupButton(R.id.connection_log_button, new OnClickListener() { @Override public void onClick(View v) { if(!loadBalancer.getStatus().contains(DELETED)){ showDialog(R.id.connection_log_button); } else { showAlert(loadBalancer.getStatus(), "Log settings cannot be edited."); } } }); setLogButtonText(); setupButton(R.id.session_persistence_button, new OnClickListener() { @Override public void onClick(View v) { if(!loadBalancer.getStatus().contains(DELETED)){ if(!loadBalancer.getProtocol().equals("HTTP")){ showAlert("Error", "Session Persistence cannot be enabled for protocols other than HTTP."); } else { showDialog(R.id.session_persistence_button); } } else { showAlert(loadBalancer.getStatus(), "Session Persistence cannot be edited."); } } }); setSessionButtonText(); setupButton(R.id.connection_throttle_button, new OnClickListener() { @Override public void onClick(View v) { if(!loadBalancer.getStatus().contains(DELETED)){ Intent editLoadBalancerIntent = new Intent(getContext(), ConnectionThrottleActivity.class); editLoadBalancerIntent.putExtra("loadBalancer", loadBalancer); startActivityForResult(editLoadBalancerIntent, EDIT_THROTTLE_CODE); } else { showAlert(loadBalancer.getStatus(), "Connection Throttle cannot be edited."); } } }); setupButton(R.id.access_control_button, new OnClickListener() { @Override public void onClick(View v) { if(!loadBalancer.getStatus().contains(DELETED)){ Intent editLoadBalancerIntent = new Intent(getContext(), AccessControlActivity.class); editLoadBalancerIntent.putExtra("loadBalancer", loadBalancer); startActivityForResult(editLoadBalancerIntent, EDIT_ACCESS_CONTROL_CODE); } else { showAlert(loadBalancer.getStatus(), "Access Control cannot be edited."); } } }); } } @Override protected Dialog onCreateDialog(int id) { switch (id) { case R.id.view_server_delete_button: return new AlertDialog.Builder(ViewLoadBalancerActivity.this) .setIcon(R.drawable.alert_dialog_icon) .setTitle("Delete Load Balancer") .setMessage("Are you sure you want to delete the load balancer?") .setPositiveButton("Delete", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { trackEvent(GoogleAnalytics.CATEGORY_LOAD_BALANCER, GoogleAnalytics.EVENT_DELETE, "", -1); new DeleteLoadBalancerTask().execute((Void[]) null); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // do nothing } }) .create(); case R.id.connection_log_button: return new AlertDialog.Builder(ViewLoadBalancerActivity.this) .setIcon(R.drawable.alert_dialog_icon) .setTitle("Disable Logs") .setMessage("Are you sure you want to disable logs for this Load Balancer?") .setPositiveButton("Enable", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { trackEvent(GoogleAnalytics.CATEGORY_LOAD_BALANCER, GoogleAnalytics.EVENT_LB_CONNECTION_LOGGING, "", -1); new SetLoggingTask().execute(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // do nothing } }) .create(); case R.id.session_persistence_button: return new AlertDialog.Builder(ViewLoadBalancerActivity.this) .setIcon(R.drawable.alert_dialog_icon) .setTitle("Session Persistence") .setMessage("Are you sure you want to disable session persistence for this Load Balancer?") .setPositiveButton("Enable", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { //trackEvent(GoogleAnalytics.CATEGORY_LOAD_BALANCER, GoogleAnalytics.EVENT_LB_SESSION_PERSISTENCE, "", -1); new SessionPersistenceTask().execute(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // do nothing } }) .create(); } return null; } @Override //Need to show different message depending on the state //of connection_logs/session_persistence protected void onPrepareDialog(int id, Dialog dialog){ if(loadBalancer != null){ switch (id) { case R.id.connection_log_button: String logTitle; String logMessage; String logButton; if(loadBalancer.getIsConnectionLoggingEnabled().equals("true")){ logTitle = "Disable Logs"; logMessage = "Are you sure you want to disable logs for this Load Balancer?"; logButton = "Disable"; } else { logTitle = "Enable Logs"; logMessage = "Log files will be processed every hour and stored in your Cloud Files account. " + "Standard Cloud Files storage and transfer fees will be accessed for the use of this feature." + "\n\nAre you sure you want to enable logs for this Load Balancer?"; logButton = "Enable"; } ((AlertDialog)dialog).setTitle(logTitle); ((AlertDialog)dialog).setMessage(logMessage); Button sessionLogButton = ((AlertDialog)dialog).getButton(AlertDialog.BUTTON1); sessionLogButton.setText(logButton); sessionLogButton.invalidate(); break; case R.id.session_persistence_button: String sessionMessage; String sessionButton; if(loadBalancer.getSessionPersistence() != null){ Log.d("info", "in sessionpersistence != null"); sessionMessage = "Are you sure you want to disable session persistence for this Load Balancer?"; sessionButton = "Disable"; } else { Log.d("info", "in sessionpersistence == null"); sessionMessage = "Are you sure you want to enable session persistence for this Load Balancer?"; sessionButton = "Enable"; } ((AlertDialog)dialog).setMessage(sessionMessage); Button sessionPersistButton = ((AlertDialog)dialog).getButton(AlertDialog.BUTTON1); sessionPersistButton.setText(sessionButton); sessionPersistButton.invalidate(); break; } } } //Displays all the load balancer data private void loadLoadBalancerData() { if(loadBalancer != null){ /* * need to update the text on button if * it has changed */ setLogButtonText(); setSessionButtonText(); TextView name = (TextView) findViewById(R.id.view_name); name.setText(loadBalancer.getName()); TextView id = (TextView) findViewById(R.id.view_lb_id); id.setText(loadBalancer.getId()); TextView protocol = (TextView) findViewById(R.id.view_protocol); protocol.setText(loadBalancer.getProtocol()); TextView port = (TextView) findViewById(R.id.view_port); port.setText(loadBalancer.getPort()); TextView algorithm = (TextView) findViewById(R.id.view_algorithm); algorithm.setText(getPrettyAlgoName(loadBalancer.getAlgorithm())); TextView status = (TextView) findViewById(R.id.view_status); if (!"ACTIVE".equals(loadBalancer.getStatus())) { status.setText(loadBalancer.getStatus()); pollLoadBalancerTask = new PollLoadBalancerTask(); pollLoadBalancerTask.execute((Void[]) null); } else { status.setText(loadBalancer.getStatus()); } status.setText(loadBalancer.getStatus()); TextView connectionLogging = (TextView) findViewById(R.id.view_islogging); String isConnectionLogging = loadBalancer.getIsConnectionLoggingEnabled(); if(isConnectionLogging != null && isConnectionLogging.equals("true")){ connectionLogging.setText("Enabled"); } else { connectionLogging.setText("Disabled"); } loadVirutalIpData(); } } private String getPrettyAlgoName(String name){ if(name == null || name.length() == 0){ return ""; } else { String result = name.charAt(0) + ""; boolean previousWasSpace = false;; for(int i = 1; i < name.length(); i++){ char curLetter = name.charAt(i); if(curLetter == '_'){ result += " "; previousWasSpace = true; } else { if(previousWasSpace){ result += Character.toUpperCase(curLetter); } else { result += Character.toLowerCase(curLetter); } previousWasSpace = false; } } return result; } } private void loadVirutalIpData() { int layoutIndex = 0; LinearLayout layout = (LinearLayout) this.findViewById(R.id.vip_addresses); layout.removeAllViews(); ArrayList<VirtualIp> virtualIps = loadBalancer.getVirtualIps(); //maybe null if the lb has been deleted if(virtualIps != null){ for (int i = 0; i < virtualIps.size(); i++) { TextView tv = new TextView(this.getBaseContext()); tv.setLayoutParams(((TextView)findViewById(R.id.view_port)).getLayoutParams()); // easy quick styling! :) tv.setTypeface(tv.getTypeface(), 1); // 1 == bold tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20); tv.setTextColor(Color.WHITE); tv.setText(virtualIps.get(i).getAddress()); tv.setGravity(((TextView)findViewById(R.id.view_port)).getGravity()); layout.addView(tv, layoutIndex++); } } loadNodeData(); } private void loadNodeData() { int layoutIndex = 0; // public IPs start here LinearLayout layout = (LinearLayout) this.findViewById(R.id.node_addresses); layout.removeAllViews(); ArrayList<Node> nodeIps = loadBalancer.getNodes(); if(nodeIps == null){ nodeIps = new ArrayList<Node>(); } /* * need to sort the addresses because during polling * their order can change and the display becomes * jumpy */ ArrayList<String> addresses = new ArrayList<String>(); for(Node n : nodeIps){ addresses.add(n.getAddress()); } Collections.sort(addresses); //may be null if lb has been deleted if(nodeIps != null){ for (int i = 0; i < nodeIps.size(); i++) { TextView tv = new TextView(this.getBaseContext()); tv.setLayoutParams(((TextView)findViewById(R.id.view_port)).getLayoutParams()); // easy quick styling! :) tv.setTypeface(tv.getTypeface(), 1); // 1 == bold tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20); tv.setTextColor(Color.WHITE); tv.setText(addresses.get(i)); tv.setGravity(((TextView)findViewById(R.id.view_port)).getGravity()); layout.addView(tv, layoutIndex++); } } } //setup menu for when menu button is pressed public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.view_loadbalancer_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.refresh_loadbalancer: new LoadLoadBalancerTask().execute((Void[]) null); return true; } return false; } @Override //have been kicked back from another activity, //so refresh the load balancer data public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { new LoadLoadBalancerTask().execute((Void[]) null); } } // HTTP request tasks private class PollLoadBalancerTask extends AsyncTask<Void, Void, LoadBalancer> { @Override protected LoadBalancer doInBackground(Void... arg0) { if(pollLoadBalancerTask.isCancelled()){ return null; } try { loadBalancer = (new LoadBalancerManager(getContext())).getLoadBalancerById(Integer.parseInt(loadBalancer.getId())); } catch (NumberFormatException e) { // we're polling, so need to show exceptions } catch (LoadBalancersException e) { // we're polling, so need to show exceptions } return loadBalancer; } @Override protected void onPostExecute(LoadBalancer result) { loadBalancer = result; loadLoadBalancerData(); } } private class LoadLoadBalancerTask extends AsyncTask<Void, Void, LoadBalancer> { private LoadBalancersException exception; private String loadBalancerId; protected void onPreExecute() { loadBalancerId = loadBalancer.getId(); /* * set to null, so if config change occurs * it will be reloaded in onCreate() */ loadBalancer = null; showDialog(); } @Override protected LoadBalancer doInBackground(Void... arg0) { LoadBalancer result = null; try { result = (new LoadBalancerManager(getContext())).getLoadBalancerById(Integer.parseInt(loadBalancerId)); } catch (LoadBalancersException e) { exception = e; } return result; } @Override protected void onPostExecute(LoadBalancer result) { hideDialog(); if (exception != null) { showAlert("Error", exception.getMessage()); } loadBalancer = result; setUpButtons(); loadLoadBalancerData(); } } public class DeleteLoadBalancerTask extends AsyncTask<Void, Void, HttpBundle> { private CloudServersException exception; @Override protected void onPreExecute(){ showDialog(); } @Override protected HttpBundle doInBackground(Void... arg0) { HttpBundle bundle = null; try { bundle = (new LoadBalancerManager(getContext())).delete(loadBalancer); } catch (CloudServersException e) { exception = e; } return bundle; } @Override protected void onPostExecute(HttpBundle bundle) { hideDialog(); HttpResponse response = bundle.getResponse(); if (response != null) { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 202) { setResult(Activity.RESULT_OK); finish(); } else { CloudServersException cse = parseCloudServersException(response); if ("".equals(cse.getMessage())) { showError("There was a problem deleting your load balancer.", bundle); } else { showError("There was a problem deleting your load balancer: " + cse.getMessage(), bundle); } } } else if (exception != null) { showError("There was a problem deleting your load balancer: " + exception.getMessage(), bundle); } } } private class SetLoggingTask extends AsyncTask<Void, Void, HttpBundle> { private CloudServersException exception; @Override protected void onPreExecute(){ //showDialog(); app.setIsSettingLogs(true); loggingListenerTask = new LoggingListenerTask(); loggingListenerTask.execute(); } @Override protected HttpBundle doInBackground(Void... arg0) { HttpBundle bundle = null; try { bundle = (new LoadBalancerManager(getContext())).setLogging(loadBalancer, !Boolean.valueOf(loadBalancer.getIsConnectionLoggingEnabled())); } catch (CloudServersException e) { exception = e; } return bundle; } @Override protected void onPostExecute(HttpBundle bundle) { //hideDialog(); app.setIsSettingLogs(false); HttpResponse response = bundle.getResponse(); if (response != null) { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 202 || statusCode == 204) { if(Boolean.valueOf(loadBalancer.getIsConnectionLoggingEnabled())){ showToast("Logging has been disabled"); } else { showToast("Logging has been enabled"); } } else { CloudServersException cse = parseCloudServersException(response); if ("".equals(cse.getMessage())) { showError("There was a problem changing your log settings.", bundle); } else { showError("There was a problem changing your log settings: " + cse.getMessage(), bundle); } } } else if (exception != null) { showError("There was a problem changing your log settings: " + exception.getMessage(), bundle); } } } /* * listens for the application to change isSettingLogs * listens so activity knows when it should display * the new settings */ private class LoggingListenerTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... arg1) { while(app.isSettingLogs()){ // wait for process to finish // or have it be canceled if(loggingListenerTask.isCancelled()){ return null; } } return null; } /* * when no longer processing, time to load * the new files */ @Override protected void onPostExecute(Void arg1) { pollLoadBalancerTask = new PollLoadBalancerTask(); pollLoadBalancerTask.execute((Void[]) null); } } private class SessionPersistenceTask extends AsyncTask<Void, Void, HttpBundle> { private CloudServersException exception; @Override protected void onPreExecute(){ app.setSettingSessionPersistence(true); sessionPersistenceListenerTask = new SessionPersistenceListenerTask(); sessionPersistenceListenerTask.execute(); } @Override protected HttpBundle doInBackground(Void... arg0) { HttpBundle bundle = null; try { String currentSetting = loadBalancer.getSessionPersistence(); if(currentSetting == null){ bundle = (new LoadBalancerManager(getContext())).setSessionPersistence(loadBalancer, "HTTP_COOKIE"); } else { bundle = (new LoadBalancerManager(getContext())).disableSessionPersistence(loadBalancer); } } catch (CloudServersException e) { exception = e; } return bundle; } @Override protected void onPostExecute(HttpBundle bundle) { //hideDialog(); app.setSettingSessionPersistence(false); HttpResponse response = bundle.getResponse(); if (response != null) { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 202 || statusCode == 200) { if(loadBalancer.getSessionPersistence() != null){ showToast("Session Persistence has been disabled"); } else { showToast("Session Persistence has been enabled"); } pollLoadBalancerTask = new PollLoadBalancerTask(); pollLoadBalancerTask.execute((Void[]) null); } else { CloudServersException cse = parseCloudServersException(response); if ("".equals(cse.getMessage())) { showError("There was a problem changing your session persistence settings.", bundle); } else { showError("There was a problem changing your session persistence settings: " + cse.getMessage(), bundle); } } } else if (exception != null) { showError("There was a problem changing your session persistence settings: " + exception.getMessage(), bundle); } } } /* * listens for the application to change isSettingSessionPersistence * listens so activity knows when it should display * the new settings */ private class SessionPersistenceListenerTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... arg1) { while(app.isSettingSessionPersistence()){ // wait for process to finish // or have it be canceled if(sessionPersistenceListenerTask.isCancelled()){ return null; } } return null; } /* * when no longer processing, time to load * the new files */ @Override protected void onPostExecute(Void arg1) { pollLoadBalancerTask = new PollLoadBalancerTask(); pollLoadBalancerTask.execute((Void[]) null); } } }