Project: android-rackspacecloud
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.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.ViewGroup; 
import android.widget.ArrayAdapter; 
import android.widget.Button; 
import android.widget.CheckBox; 
import android.widget.CompoundButton; 
import android.widget.CompoundButton.OnCheckedChangeListener; 
import android.widget.LinearLayout; 
import android.widget.ListView; 
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.Node; 
import com.rackspace.cloud.loadbalancer.api.client.NodeManager; 
import com.rackspace.cloud.servers.api.client.CloudServersException; 
import com.rackspace.cloud.servers.api.client.Server; 
import com.rackspace.cloud.servers.api.client.ServerManager; 
import com.rackspace.cloud.servers.api.client.http.HttpBundle; 
 
public class AddMoreNodesActivity extends CloudListActivity { 
 
 private static final int ADD_NODE_CODE = 178
 private static final int ADD_EXTERNAL_NODE_CODE = 188
 private ArrayList<Server> possibleNodes;  
 //the last position in the listview that was clicked 
 private int lastCheckedPos; 
 //the location in nodes of the last node that was clicked 
 private int positionOfNode; 
 private ArrayList<Node> nodes; 
 private ArrayList<Node> nodesToAdd; 
 private LoadBalancer loadBalancer; 
 
 @SuppressWarnings("unchecked"
 @Override 
 public void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  nodes = (ArrayList<Node>) this.getIntent().getExtras().get("nodes"); 
  loadBalancer = (LoadBalancer) this.getIntent().getExtras().get("loadBalancer"); 
  setContentView(R.layout.addnodes); 
  restoreState(savedInstanceState); 
 
 
 @Override 
 protected void onSaveInstanceState(Bundle outState) { 
  super.onSaveInstanceState(outState); 
 
  outState.putSerializable("nodes", nodes); 
  outState.putSerializable("loadBalancer", loadBalancer); 
  outState.putSerializable("nodesToAdd", nodesToAdd); 
  outState.putSerializable("possibleNodes", possibleNodes); 
  outState.putInt("lastCheckedPos", lastCheckedPos); 
  outState.putInt("positionOfNode", positionOfNode); 
 
 
 @SuppressWarnings("unchecked"
 protected void restoreState(Bundle state) { 
  super.restoreState(state); 
 
  if (state != null && state.containsKey("nodes")){ 
   nodes = (ArrayList<Node>) state.getSerializable("nodes"); 
   if(nodes == null){ 
    nodes = new ArrayList<Node>(); 
   
  
 
  if (state != null && state.containsKey("loadBalancer")){ 
   loadBalancer = (LoadBalancer) state.getSerializable("loadBalancer"); 
   if(loadBalancer == null){ 
    loadBalancer = new LoadBalancer(); 
   
  
 
  if (state != null && state.containsKey("lastCheckedPos")){ 
   lastCheckedPos = (Integer) state.getSerializable("lastCheckedPos"); 
  
 
  if (state != null && state.containsKey("positionOfNode")){ 
   positionOfNode = (Integer) state.getSerializable("positionOfNode"); 
  
 
  if (state != null && state.containsKey("nodesToAdd")){ 
   nodesToAdd = (ArrayList<Node>) state.getSerializable("nodesToAdd"); 
  
  else
   nodesToAdd = new ArrayList<Node>(); 
  
 
  if (state != null && state.containsKey("possibleNodes") && state.getSerializable("possibleNodes") != null) {  
   possibleNodes = (ArrayList<Server>) state.getSerializable("possibleNodes"); 
   if (possibleNodes.size() == 0) { 
    displayNoServersCell(); 
   else { 
    getListView().setDividerHeight(1); // restore divider lines 
    setListAdapter(new ServerAdapter()); 
   
  else { 
   loadServers(); 
  
 
  Button submitNodes = (Button) findViewById(R.id.submit_nodes_button); 
  submitNodes.setOnClickListener(new OnClickListener() { 
 
   @Override 
   public void onClick(View v) { 
    if(nodesToAdd.size() == 0){ 
     finish(); 
    else { 
     trackEvent(GoogleAnalytics.CATEGORY_LOAD_BALANCER, GoogleAnalytics.EVENT_ADD_LB_NODES, "", -1); 
     new AddNodesTask().execute(); 
    
   
  }); 
 
  Button addExternalNode = (Button) findViewById(R.id.add_external_node); 
  addExternalNode.setOnClickListener(new OnClickListener() { 
 
   @Override 
   public void onClick(View v) { 
    positionOfNode = -1
    lastCheckedPos = -1
    Intent viewIntent = new Intent(getContext(), AddExternalNodeActivity.class); 
    viewIntent.putExtra("loadBalancerPort", loadBalancer.getPort()); 
    viewIntent.putExtra("weighted", loadBalancer.getAlgorithm().toLowerCase().contains("weighted")); 
    startActivityForResult(viewIntent, ADD_EXTERNAL_NODE_CODE); 
   
  }); 
 
 
 @Override 
 public void onBackPressed(){ 
  setResult(RESULT_CANCELED); 
  finish(); 
 
 
 //When a list item is click just change the checkbox state 
 //and then the checkbox's onClick will be performed 
 protected void onListItemClick(ListView l, View v, int position, long id) { 
  if (possibleNodes != null && possibleNodes.size() > 0) { 
   if(!possibleNodes.get(position).getName().equals("External Node")){ 
    LinearLayout linear = (LinearLayout) findViewById(R.id.nodes_linear_layout);  
    ListView serversList = (ListView) linear.findViewById(android.R.id.list); 
    View row = serversList.getChildAt(position); 
    CheckBox checkBox = (CheckBox)row.findViewById(R.id.add_node_checkbox); 
    if(!checkBox.isChecked()){ 
     //if the checkbox was not previously checked, treat the listItemClick 
     //the same as checking the checkbox 
     checkBox.setChecked(!checkBox.isChecked()); 
    else { 
     //if the checkbox was already checked when the listItemClick occurred, 
     //then treat it like an edit 
 
     Server server = possibleNodes.get(position); 
 
     //Need to put all the ip's of the server into one 
     //list so they can all be displayed in one spinner 
     String[] ipAddresses = getAllIpsOfServer(server); 
 
     Node node = getNodeFromServer(server); 
 
     positionOfNode = findNodePosition(node); 
     lastCheckedPos = position; 
 
     Intent viewIntent = new Intent(getContext(), AddNodeActivity.class); 
     viewIntent.putExtra("ipAddresses", ipAddresses); 
     viewIntent.putExtra("name", server.getName()); 
     if(node != null){ 
      viewIntent.putExtra("node", node); 
     
     viewIntent.putExtra("weighted", loadBalancer.getAlgorithm().toLowerCase().contains("weighted")); 
     startActivityForResult(viewIntent, ADD_NODE_CODE); 
    
   else { 
    //When clicked on an external node 
    Server server = possibleNodes.get(position); 
    Node node = getNodeFromServer(server); 
    positionOfNode = findNodePosition(node); 
    lastCheckedPos = position; 
    Intent viewIntent = new Intent(getContext(), AddExternalNodeActivity.class); 
    if(node != null){ 
     viewIntent.putExtra("node", node); 
    
    //weighted is false, because on initial node add 
    //weight is not option 
    viewIntent.putExtra("weighted"false); 
    startActivityForResult(viewIntent, ADD_EXTERNAL_NODE_CODE); 
   
  
 
 
 //return the location of node in nodes 
 //if it is no in there then -1 
 private int findNodePosition(Node node){ 
  for(int i = 0; i < nodesToAdd.size(); i++){ 
   String address = node.getAddress(); 
   if(address.equals(nodesToAdd.get(i).getAddress())){ 
    return i; 
   
  
  return -1
 
 
 private void displayNoServersCell() { 
  String a[] = new String[1]; 
  a[0] = "No Servers"
  setListAdapter(new ArrayAdapter<String>(this, R.layout.noserverscell2, R.id.no_servers_label, a)); 
  getListView().setTextFilterEnabled(true); 
  getListView().setDividerHeight(0); // hide the dividers so it won't look like a list row 
  getListView().setItemsCanFocus(false); 
 
 
 private void setServerList(ArrayList<Server> servers) { 
  if (servers == null) { 
   servers = new ArrayList<Server>(); 
  
 
  for(int i = 0; i < servers.size(); i++) { 
   /*
    * if all the IP's of a server are 
    * already used as nodes, we do not  
    * need to display that server  
    */
 
   if(!notAllIpsNodes(servers.get(i))){ 
    servers.remove(i); 
   
  
 
  String[] serverNames = new String[servers.size()]; 
  this.possibleNodes = new ArrayList<Server>(); 
 
  for(int i = 0; i < servers.size(); i++){ 
   serverNames[i] = servers.get(i).getName(); 
   this.possibleNodes.add(i, servers.get(i)); 
  
 
  if (serverNames.length == 0) { 
   displayNoServersCell(); 
  else { 
   getListView().setDividerHeight(1); // restore divider lines  
   setListAdapter(new ServerAdapter()); 
  
 
 
 /*
  * determine if all the IP's of a server are 
  * already used as nodes 
  */
 
 private boolean notAllIpsNodes(Server server){ 
  for(String address : server.getPrivateIpAddresses()){ 
   if(!nodeHasAddress(address)){ 
    return true
   
  
  for(String address : server.getPublicIpAddresses()){ 
   if(!nodeHasAddress(address)){ 
    return true
   
  
  return false
 
 
 /*
  * determine is an existing node has IP Address, 
  * address 
  */
 
 private boolean nodeHasAddress(String address){ 
  for(Node n : nodes){ 
   if(n.getAddress().equals(address)){ 
    return true
   
  
  return false
 
 
 private void loadServers() { 
  new LoadServersTask().execute((Void[]) null); 
 
 
 // * Adapter/ 
 class ServerAdapter extends ArrayAdapter<Server> { 
  ServerAdapter() { 
   super(AddMoreNodesActivity.this, R.layout.listservernodecell, possibleNodes); 
  
 
  public View getView(int position, View convertView, ViewGroup parent) { 
 
   final Server server = possibleNodes.get(position); 
   LayoutInflater inflater = getLayoutInflater(); 
   View row = inflater.inflate(R.layout.listservernodecell, parent, false); 
 
   TextView label = (TextView) row.findViewById(R.id.label); 
   label.setText(server.getName()); 
 
   TextView sublabel = (TextView) row.findViewById(R.id.sublabel); 
   if(server.getName().equals("External Node")){ 
    sublabel.setText(server.getPrivateIpAddresses()[0]); 
   else { 
    sublabel.setText(server.getFlavor().getName() + " - " + server.getImage().getName()); 
   
 
   String[] publicIp = server.getPublicIpAddresses(); 
   String[] privateIp = server.getPrivateIpAddresses(); 
 
   if(publicIp == null){ 
    publicIp = new String[0]; 
   
 
   if(privateIp == null){ 
    privateIp = new String[0]; 
   
 
   ArrayList<String> ipAddressList = new ArrayList<String>(); 
   for(int i = 0; i < privateIp.length; i++){ 
    if(!nodeHasAddress(privateIp[i])){ 
     ipAddressList.add(privateIp[i]); 
    
   
   for(int i = 0; i < publicIp.length; i++){ 
    if(!nodeHasAddress(publicIp[i])){ 
     ipAddressList.add(publicIp[i]); 
    
   
 
   final String[] ipAddresses = ipAddressList.toArray(new String[ipAddressList.size()]); 
   final int pos = position; 
   CheckBox add = (CheckBox) row.findViewById(R.id.add_node_checkbox); 
 
   if(inToAddList(server)){ 
    add.setChecked(true); 
   
 
   add.setOnCheckedChangeListener(new OnCheckedChangeListener() { 
 
    @Override 
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
     if(isChecked){ 
      //if node is being check it won't be in nodes positionOfNode is -1 
      positionOfNode = -1
      lastCheckedPos = pos; 
      Intent viewIntent = new Intent(getContext(), AddNodeActivity.class); 
      viewIntent.putExtra("ipAddresses", ipAddresses); 
      viewIntent.putExtra("name", server.getName()); 
      viewIntent.putExtra("loadBalancerPort", loadBalancer.getPort()); 
      viewIntent.putExtra("weighted", loadBalancer.getAlgorithm().contains("WEIGHTED")); 
      startActivityForResult(viewIntent, ADD_NODE_CODE); 
     
     else
      removeNodeFromList(server); 
      if(server.getName().equals("External Node")){ 
       possibleNodes.remove(server); 
       setServerList(possibleNodes); 
      
     
    
   }); 
 
   return(row); 
  
 
  /*
   *  need to remove by id because that is  
   *  what is unique 
   */
 
  private void removeNodeFromList(Server server){ 
   for(int i = 0; i < nodesToAdd.size(); i++){ 
    Node node = nodesToAdd.get(i); 
    if(serverHasIp(server, node.getAddress())){ 
     nodesToAdd.remove(i); 
     break
    
   
  
 
 private boolean serverHasIp(Server server, String address){ 
  String[] addresses = server.getPrivateIpAddresses(); 
  if(addresses != null){ 
   for(int i = 0; i < addresses.length; i++){ 
    if(addresses[i].equals(address)){ 
     return true
    
   
  
  addresses = server.getPublicIpAddresses(); 
  if(addresses != null){ 
   for(int i = 0; i < addresses.length; i++){ 
    if(addresses[i].equals(address)){ 
     return true
    
   
  
  return false
 
 
 private boolean inToAddList(Server server){ 
  for(Node node : nodesToAdd){ 
   if(serverHasIp(server, node.getAddress())){ 
    return true
   
  
  return false
 
 
 
 private class AddNodesTask extends AsyncTask<Void, Void, HttpBundle> { 
  private CloudServersException exception; 
 
  protected void onPreExecute(){ 
   showDialog(); 
  
 
  @Override 
  protected HttpBundle doInBackground(Void... arg0) { 
   HttpBundle bundle = null
   try { 
    bundle = (new NodeManager(getContext())).add(loadBalancer, nodesToAdd); 
   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 class LoadServersTask extends AsyncTask<Void, Void, ArrayList<Server>> { 
  private CloudServersException exception; 
 
  @Override 
  protected void onPreExecute(){ 
   showDialog(); 
  
 
  @Override 
  protected ArrayList<Server> doInBackground(Void... arg0) { 
   ArrayList<Server> servers = null
   try { 
    servers = (new ServerManager()).createList(true, getContext()); 
   catch (CloudServersException e) { 
    exception = e;     
   }  
   return servers; 
  
 
  @Override 
  protected void onPostExecute(ArrayList<Server> result) { 
   hideDialog(); 
   if (exception != null) { 
    showAlert("Error", exception.getMessage()); 
   
   setServerList(result); 
  
 
 
 private String getNameFromIp(String address){ 
  for(Server s: possibleNodes){ 
   if(serverHasIp(s, address)){ 
    return s.getName(); 
   
  
  return ""
 
 
 private boolean ipInList(String address){ 
  for(Server s : possibleNodes){ 
   if(serverHasIp(s, address) && !s.getName().equals("External Node")){ 
    return true
   
  
  return false
 
 
 //returns the node that is using an ip from server 
 private Node getNodeFromServer(Server server){ 
  for(Node node : nodesToAdd){ 
   if(serverHasIp(server, node.getAddress())){ 
    return node; 
   
  
  return null
 
 
 //returns an array of all the ip's of server 
 private String[] getAllIpsOfServer(Server server){ 
  String[] publicIp = server.getPublicIpAddresses(); 
  String[] privateIp = server.getPrivateIpAddresses(); 
  if(publicIp == null){ 
   publicIp = new String[0]; 
  
  if(privateIp == null){ 
   privateIp = new String[0]; 
  
  String[] ipAddresses = new String[privateIp.length + publicIp.length]; 
  for(int i = 0; i < privateIp.length; i++){ 
   ipAddresses[i] = privateIp[i]; 
  
  for(int i = 0; i < publicIp.length; i++){ 
   ipAddresses[i+privateIp.length] = publicIp[i]; 
  
 
  return ipAddresses; 
 
 
 protected void onActivityResult(int requestCode, int resultCode, Intent data){ 
  int pos = lastCheckedPos; 
  if(requestCode == ADD_NODE_CODE && resultCode == RESULT_OK){ 
   //data will be null if user backed out on edit 
   //we dont need to do anything then 
   //if new node added data won't be null 
   //so create the new node and add it to the list 
   if(data != null){ 
    //will remove the node if it's already in the list  
    //so we can update it 
    if(positionOfNode >= 0){ 
     nodesToAdd.remove(positionOfNode); 
    
 
    Node node = new Node(); 
    node.setAddress(data.getStringExtra("nodeIp")); 
    node.setCondition(data.getStringExtra("nodeCondition")); 
    node.setName(possibleNodes.get(pos).getName()); 
    node.setPort(data.getStringExtra("nodePort")); 
    node.setWeight(data.getStringExtra("nodeWeight")); 
    nodesToAdd.add(node); 
   
  
  else if(requestCode == ADD_NODE_CODE && resultCode == RESULT_CANCELED){ 
   //uncheck the node at lastCheckedPos 
   LinearLayout linear = (LinearLayout) findViewById(R.id.nodes_linear_layout);  
   ListView serversList = (ListView) linear.findViewById(android.R.id.list); 
   View row = serversList.getChildAt(pos); 
   CheckBox checkBox = (CheckBox)row.findViewById(R.id.add_node_checkbox); 
   checkBox.setChecked(false); 
  
  else if(requestCode == ADD_EXTERNAL_NODE_CODE && resultCode == RESULT_OK){ 
   Node node = new Node(); 
   node.setAddress(data.getStringExtra("nodeIp")); 
   node.setCondition(data.getStringExtra("nodeCondition")); 
   node.setName("External Node"); 
   node.setPort(data.getStringExtra("nodePort")); 
   node.setWeight(data.getStringExtra("nodeWeight")); 
 
   /*
    * If the ip is from a cloud server or already added, alert to user 
    * so they can select it from there 
    */
  
   String nodeIP = node.getAddress(); 
   ArrayList<Node> lbNodes = loadBalancer.getNodes(); 
   boolean nodeIpExists = false
   for(int i = 0; i < lbNodes.size(); i++){ 
    if(nodeIP.equals(lbNodes.get(i).getAddress())){ 
     nodeIpExists = true
    
   
   if(nodeIpExists){ 
     showAlert("Error""This IP has already been added as an external node, please edit " + 
     "it from the list."); 
   else if(!ipInList(node.getAddress())){ 
     
     
    if(positionOfNode >= 0){ 
     nodesToAdd.remove(positionOfNode); 
    
 
    nodesToAdd.add(node); 
    //Add it to server list so it display in the listview 
    Server server = new Server(); 
    server.setName("External Node"); 
    String[] ip = {data.getStringExtra("nodeIp")}; 
    server.setPrivateIpAddresses(ip); 
    if(pos != -1){ 
     possibleNodes.remove(pos); 
    
    possibleNodes.add(server); 
    setServerList(possibleNodes); 
   else { 
    String name = getNameFromIp(node.getAddress()); 
    if(name.equals("External Node")){ 
     showAlert("Error""This IP has already been added as an external node, please edit " + 
     "it from the list."); 
    else { 
     showAlert("Error""This IP belongs to a cloud server: \"" + getNameFromIp(node.getAddress())  
       "\", please edit it from the list."); 
    
   
  
  printTheNodes(); 
 
 
 private void printTheNodes(){ 
  for(Node n: nodesToAdd){ 
   Log.d("info""address: " + n.getAddress() + " Port: " + n.getPort() + " Cond: " + n.getCondition()); 
  
  Log.d("info"" SPACE "); 
 
}