package com.rackspacecloud.android; import java.util.ArrayList; import org.apache.http.HttpResponse; import android.app.Activity; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.TableRow; import com.rackspace.cloud.android.R; import com.rackspace.cloud.loadbalancer.api.client.Algorithm; 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.Protocol; import com.rackspace.cloud.loadbalancer.api.client.VirtualIp; import com.rackspace.cloud.servers.api.client.Account; import com.rackspace.cloud.servers.api.client.CloudServersException; import com.rackspace.cloud.servers.api.client.Server; import com.rackspace.cloud.servers.api.client.http.HttpBundle; public class AddLoadBalancerActivity extends CloudActivity implements OnItemSelectedListener { private static final String[] VIP_TYPES = {"Public", "ServiceNet", "Shared"}; private static final int ADD_NODES_ACTIVITY_CODE = 165; private static final int SHARED_VIP_ACTIVITY_CODE = 235; private ArrayList<Node> nodes; private ArrayList<Server> possibleNodes; private LoadBalancer loadBalancer; private Protocol[] protocols; private Protocol selectedProtocol; private Algorithm[] algorithms; private Algorithm selectedAlgorithm; private VirtualIp selectedVip; private EditText portEditText; private Spinner protocolSpinner; private Spinner protocolSubSpinner; private Spinner algorithmSpinner; private Spinner vipSpinner; private Spinner regionSpinner; private Button selectVipButton; private Button selectNodesButton; private String selectedVipType; private String selectedRegion; private String selectedName; private String selectedPort; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); trackPageView(GoogleAnalytics.PAGE_ADD_LOADBALANCER); setContentView(R.layout.view_add_loadbalancer); restoreState(savedInstanceState); } @SuppressWarnings("unchecked") protected void restoreState(Bundle state) { super.restoreState(state); if(state != null && state.containsKey("nodes")){ nodes = (ArrayList<Node>) state.getSerializable("nodes"); } else{ nodes = new ArrayList<Node>(); } if(state != null && state.containsKey("possibleNodes")){ possibleNodes = (ArrayList<Server>) state.getSerializable("possibleNodes"); } else{ possibleNodes = new ArrayList<Server>(); } if(state != null && state.containsKey("selectedVip")){ selectedVip = (VirtualIp) state.getSerializable("selectedVip"); } setupText(); loadProtocolSpinner(); loadProtocolSubSpinner(); loadAlgorithmSpinner(); loadVipSpinner(); loadRegionSpinner(); setUpButtons(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("nodes", nodes); outState.putSerializable("possibleNodes", possibleNodes); outState.putSerializable("selectedVip", selectedVip); } public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (parent == protocolSpinner) { TableRow customProtocol = (TableRow)findViewById(R.id.custom_protocol_row); if(position < protocols.length){ selectedProtocol = protocols[position]; selectedPort = protocols[position].getDefaultPort(); customProtocol.setVisibility(View.GONE); } else { customProtocol.setVisibility(View.VISIBLE); } updateVipIndicatorLight(); } else if (parent == algorithmSpinner){ selectedAlgorithm = algorithms[position]; } else if (parent == vipSpinner){ selectedVipType = VIP_TYPES[position]; if(VIP_TYPES[position].equals("Shared")){ ((TableRow) findViewById(R.id.select_vip_layout)).setVisibility(View.VISIBLE); } else { ((TableRow) findViewById(R.id.select_vip_layout)).setVisibility(View.GONE); } updateVipIndicatorLight(); } else if (parent == regionSpinner){ selectedRegion = Account.getAccount().getLoadBalancerRegions()[position]; updateVipIndicatorLight(); } else if (parent == protocolSubSpinner){ selectedProtocol = protocols[position]; updateVipIndicatorLight(); } } public void onNothingSelected(AdapterView<?> parent) { } private void setUpButtons(){ selectVipButton = (Button) findViewById(R.id.selected_shared_vip); updateVipIndicatorLight(); selectVipButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent viewIntent = new Intent(getApplicationContext(), SharedVipActivity.class); viewIntent.putExtra("loadBalancerPort", selectedPort); viewIntent.putExtra("loadBalancerRegion", selectedRegion); viewIntent.putExtra("selectedVip", selectedVip); startActivityForResult(viewIntent, SHARED_VIP_ACTIVITY_CODE); } }); ((TableRow) findViewById(R.id.select_vip_layout)).setVisibility(View.GONE); selectNodesButton = (Button) findViewById(R.id.add_nodes_button); updateNodesIndicatorLight(); selectNodesButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent viewIntent = new Intent(getApplicationContext(), AddNodesActivity.class); viewIntent.putExtra("nodes", nodes); if(validPort(selectedPort)){ viewIntent.putExtra("loadBalancerPort", selectedPort); } viewIntent.putExtra("possibleNodes", possibleNodes); startActivityForResult(viewIntent, ADD_NODES_ACTIVITY_CODE); } }); Button addLoadBalancer = (Button) findViewById(R.id.add_lb_button); addLoadBalancer.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { selectedName = ((EditText)findViewById(R.id.edit_lb_name_text)).getText().toString(); //selectedPort = ((EditText)findViewById(R.id.edit_port_text)).getText().toString(); if(!validName()){ showAlert("Error", "Load balancer name cannot be blank."); } else if(!validPort(selectedPort)){ showAlert("Error", "Must have a protocol port number that is between 1 and 65535."); } else if(!validVip()){ showAlert("Error", "Please select a valid Virtual IP."); } else if(!validNodes()){ showAlert("Error", "You must select at least one enabled cloud server or add and enable at least one external node."); } else { loadBalancer = new LoadBalancer(); loadBalancer.setName(selectedName); loadBalancer.setProtocol(selectedProtocol.getName()); loadBalancer.setPort(selectedPort); loadBalancer.setVirtualIpType(selectedVipType); loadBalancer.setAlgorithm(selectedAlgorithm.getName()); loadBalancer.setRegion(selectedRegion); loadBalancer.setNodes(nodes); if(selectedVip != null){ ArrayList<VirtualIp> vips = new ArrayList<VirtualIp>(); vips.add(selectedVip); loadBalancer.setVirtualIps(vips); } trackEvent(GoogleAnalytics.CATEGORY_LOAD_BALANCER, GoogleAnalytics.EVENT_CREATE, "", -1); new AddLoadBalancerTask().execute(); Log.d("info", "the port is " + selectedPort); } } }); } private boolean validName(){ return !selectedName.equals(""); } private boolean validPort(String selectedPort){ boolean result; try{ result = !selectedPort.equals("") && Integer.valueOf(selectedPort) > 0 && Integer.valueOf(selectedPort) < 65536; } catch (NumberFormatException e){ result = false; } return result; } private boolean validNodes(){ boolean exist = nodes != null && nodes.size() > 0; boolean enabled = false; for(Node n: nodes){ enabled = enabled || n.getCondition().equalsIgnoreCase("enabled"); } return exist && enabled; } private boolean validVip(){ /* * assign selectedVipType to the * first value in the list, the default * if its null */ if(selectedVipType == null){ selectedVipType = VIP_TYPES[0]; } return !selectedVipType.equalsIgnoreCase("Shared") ||(selectedVip != null && !selectedVip.getLoadBalancer().getPort().equals(selectedPort) && selectedVip.getLoadBalancer().getRegion().equals(selectedRegion)); } private void updateNodesIndicatorLight(){ if(validNodes()){ selectNodesButton.setCompoundDrawablesWithIntrinsicBounds(0,0,0,0); } else { selectNodesButton.setCompoundDrawablesWithIntrinsicBounds(0,0,R.drawable.ic_notification_overlay,0); } } private void updateVipIndicatorLight(){ if(validVip()){ selectVipButton.setCompoundDrawablesWithIntrinsicBounds(0,0,0,0); } else { selectVipButton.setCompoundDrawablesWithIntrinsicBounds(0,0,R.drawable.ic_notification_overlay,0); } } private void setupText(){ portEditText = (EditText)findViewById(R.id.edit_port_text); portEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { selectedPort = s.toString(); updateVipIndicatorLight(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // do nothing } @Override public void afterTextChanged(Editable s) { // do nothing } }); } private void loadRegionSpinner() { regionSpinner = (Spinner) findViewById(R.id.edit_region_spinner); regionSpinner.setOnItemSelectedListener(this); ArrayAdapter<String> regionAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, Account.getAccount().getLoadBalancerRegions()); regionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); regionSpinner.setAdapter(regionAdapter); } private void loadVipSpinner() { vipSpinner = (Spinner) findViewById(R.id.edit_vip_spinner); vipSpinner.setOnItemSelectedListener(this); ArrayAdapter<String> vipAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, VIP_TYPES); vipAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); vipSpinner.setAdapter(vipAdapter); } private void loadProtocolSpinner() { protocolSpinner = (Spinner) findViewById(R.id.edit_protocol_spinner); protocolSpinner.setOnItemSelectedListener(this); String protocolNames[] = new String[Protocol.getProtocols().size() + 1]; protocols = new Protocol[Protocol.getProtocols().size()]; int httpIndex = 0; for(int i = 0; i < Protocol.getProtocols().size(); i++){ protocols[i] = Protocol.getProtocols().get(i); protocolNames[i] = Protocol.getProtocols().get(i).getName() + " (" + Protocol.getProtocols().get(i).getDefaultPort() + ")"; if(Protocol.getProtocols().get(i).getName().equals("HTTP")){ httpIndex = i; } } protocolNames[protocolNames.length - 1] = "Custom"; ArrayAdapter<String> protocolAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, protocolNames); protocolAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); protocolSpinner.setAdapter(protocolAdapter); protocolSpinner.setSelection(httpIndex); } /* * this is the spinner for protocol selection that * appears if custom is chosen from protocolSpinner */ private void loadProtocolSubSpinner() { protocolSubSpinner = (Spinner) findViewById(R.id.edit_protocol_sub_spinner); protocolSubSpinner.setOnItemSelectedListener(this); String protocolNames[] = new String[Protocol.getProtocols().size()]; for(int i = 0; i < Protocol.getProtocols().size(); i++){ protocolNames[i] = Protocol.getProtocols().get(i).getName(); } ArrayAdapter<String> protocolAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, protocolNames); protocolAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); protocolSubSpinner.setAdapter(protocolAdapter); } private void loadAlgorithmSpinner() { algorithmSpinner = (Spinner) findViewById(R.id.edit_algorithm_spinner); algorithmSpinner.setOnItemSelectedListener(this); String algorithmNames[] = new String[Algorithm.getAlgorithms().size()]; algorithms = new Algorithm[Algorithm.getAlgorithms().size()]; for(int i = 0; i < Algorithm.getAlgorithms().size(); i++){ algorithms[i] = Algorithm.getAlgorithms().get(i); algorithmNames[i] = getPrettyAlgoName(Algorithm.getAlgorithms().get(i).getName()); } ArrayAdapter<String> algorithmAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, algorithmNames); algorithmAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); algorithmSpinner.setAdapter(algorithmAdapter); } 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 class AddLoadBalancerTask extends AsyncTask<Void, Void, HttpBundle> { private CloudServersException exception; protected void onPreExecute(){ showDialog(); } @Override protected HttpBundle doInBackground(Void... arg0) { HttpBundle bundle = null; try { bundle = (new LoadBalancerManager(getContext())).create(loadBalancer, LoadBalancer.getRegionUrl(selectedRegion)); } 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 creating your load balancer.", bundle); } else { //if container with same name already exists showError("There was a problem creating your load balancer: " + cse.getMessage() + "\n See details for more information", bundle); } } } else if (exception != null) { showError("There was a problem creating your container: " + exception.getMessage()+"\n See details for more information.", bundle); } finish(); } } private void printNodes(ArrayList<Node> nodes){ for(Node n : nodes){ Log.d("info", "node is: " + n.getAddress()); } } @SuppressWarnings("unchecked") @Override protected void onActivityResult (int requestCode, int resultCode, Intent data){ if(requestCode == ADD_NODES_ACTIVITY_CODE && resultCode == RESULT_OK){ //set node list nodes = ((ArrayList<Node>)data.getSerializableExtra("nodes")); updateNodesIndicatorLight(); printNodes(nodes); } else if(requestCode == ADD_NODES_ACTIVITY_CODE && resultCode == RESULT_CANCELED){ //don't change list } else if(requestCode == SHARED_VIP_ACTIVITY_CODE){ if(data != null){ selectedVip = (VirtualIp)data.getSerializableExtra("selectedVip"); } updateVipIndicatorLight(); } } }