Revision 7dbfc514
b/AndroidManifest.xml | ||
---|---|---|
3 | 3 |
android:versionCode="3" android:versionName="1.2" package="com.rackspace.cloud.android"> |
4 | 4 |
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> |
5 | 5 |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission> |
6 |
<application android:name="AndroidCloudApplication" android:icon="@drawable/rackspace60" |
|
6 |
<application android:name=".AndroidCloudApplication" android:icon="@drawable/rackspace60"
|
|
7 | 7 |
android:label="@string/app_name" android:debuggable="true"> |
8 | 8 |
<activity android:name=".RackspaceCloudActivity" |
9 | 9 |
android:label="@string/app_name"> |
b/src/com/rackspace/cloud/android/AccessControlActivity.java | ||
---|---|---|
1 |
package com.rackspace.cloud.android; |
|
2 |
|
|
3 |
import java.util.ArrayList; |
|
4 |
|
|
5 |
import org.apache.http.HttpResponse; |
|
6 |
|
|
7 |
import android.app.Activity; |
|
8 |
import android.app.AlertDialog; |
|
9 |
import android.app.Dialog; |
|
10 |
import android.content.DialogInterface; |
|
11 |
import android.content.Intent; |
|
12 |
import android.os.AsyncTask; |
|
13 |
import android.os.Bundle; |
|
14 |
import android.view.LayoutInflater; |
|
15 |
import android.view.View; |
|
16 |
import android.view.View.OnClickListener; |
|
17 |
import android.view.ViewGroup; |
|
18 |
import android.widget.ArrayAdapter; |
|
19 |
import android.widget.Button; |
|
20 |
import android.widget.ImageView; |
|
21 |
import android.widget.ListView; |
|
22 |
import android.widget.TextView; |
|
23 |
|
|
24 |
import com.rackspace.cloud.android.R; |
|
25 |
import com.rackspace.cloud.loadbalancer.api.client.LoadBalancer; |
|
26 |
import com.rackspace.cloud.loadbalancer.api.client.NetworkItem; |
|
27 |
import com.rackspace.cloud.loadbalancer.api.client.NetworkItemManager; |
|
28 |
import com.rackspace.cloud.loadbalancer.api.client.http.LoadBalancersException; |
|
29 |
import com.rackspace.cloud.servers.api.client.CloudServersException; |
|
30 |
import com.rackspace.cloud.servers.api.client.http.HttpBundle; |
|
31 |
|
|
32 |
public class AccessControlActivity extends CloudListActivity { |
|
33 |
|
|
34 |
private final int REMOVE_RULE = 199; |
|
35 |
private final int ADD_RULE = 219; |
|
36 |
|
|
37 |
private LoadBalancer loadBalancer; |
|
38 |
private ArrayList<NetworkItem> networkItems; |
|
39 |
private int lastSelectedRulePosition; |
|
40 |
|
|
41 |
@Override |
|
42 |
public void onCreate(Bundle savedInstanceState) { |
|
43 |
super.onCreate(savedInstanceState); |
|
44 |
loadBalancer = (LoadBalancer) this.getIntent().getExtras().get("loadBalancer"); |
|
45 |
setContentView(R.layout.accesscontrol); |
|
46 |
restoreState(savedInstanceState); |
|
47 |
} |
|
48 |
|
|
49 |
@Override |
|
50 |
protected void onSaveInstanceState(Bundle outState) { |
|
51 |
super.onSaveInstanceState(outState); |
|
52 |
outState.putSerializable("networkItems", networkItems); |
|
53 |
} |
|
54 |
|
|
55 |
@SuppressWarnings("unchecked") |
|
56 |
protected void restoreState(Bundle state) { |
|
57 |
super.restoreState(state); |
|
58 |
|
|
59 |
setupButton(); |
|
60 |
|
|
61 |
if (state != null && state.containsKey("networkItems") && state.getSerializable("networkItems") != null) { |
|
62 |
networkItems = (ArrayList<NetworkItem>) state.getSerializable("networkItems"); |
|
63 |
if (networkItems.size() == 0) { |
|
64 |
displayNoRulesCell(); |
|
65 |
} else { |
|
66 |
getListView().setDividerHeight(1); // restore divider lines |
|
67 |
setListAdapter(new NetworkItemAdapter()); |
|
68 |
} |
|
69 |
} else { |
|
70 |
loadNetworkItems(); |
|
71 |
} |
|
72 |
} |
|
73 |
|
|
74 |
private void setupButton(){ |
|
75 |
Button addRule = (Button)findViewById(R.id.add_rule_button); |
|
76 |
addRule.setOnClickListener(new OnClickListener() { |
|
77 |
|
|
78 |
@Override |
|
79 |
public void onClick(View v) { |
|
80 |
Intent viewIntent = new Intent(getContext(), AddAccessRuleActivity.class); |
|
81 |
viewIntent.putExtra("loadBalancer", loadBalancer); |
|
82 |
startActivityForResult(viewIntent, ADD_RULE); |
|
83 |
} |
|
84 |
}); |
|
85 |
} |
|
86 |
|
|
87 |
protected void onListItemClick(ListView l, View v, int position, long id) { |
|
88 |
if (networkItems != null && networkItems.size() > 0) { |
|
89 |
lastSelectedRulePosition = position; |
|
90 |
showDialog(REMOVE_RULE); |
|
91 |
} |
|
92 |
} |
|
93 |
|
|
94 |
@Override |
|
95 |
protected Dialog onCreateDialog(int id) { |
|
96 |
switch (id) { |
|
97 |
case REMOVE_RULE: |
|
98 |
return new AlertDialog.Builder(AccessControlActivity.this) |
|
99 |
.setIcon(R.drawable.alert_dialog_icon) |
|
100 |
.setTitle("Remove Rule") |
|
101 |
.setMessage("Would you like to remove this rule?") |
|
102 |
.setPositiveButton("Remove", new DialogInterface.OnClickListener() { |
|
103 |
public void onClick(DialogInterface dialog, int whichButton) { |
|
104 |
new DeleteNetworkItemTask().execute((Void[]) null); |
|
105 |
} |
|
106 |
}) |
|
107 |
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { |
|
108 |
public void onClick(DialogInterface dialog, int whichButton) { |
|
109 |
// User clicked Cancel so do some stuff |
|
110 |
} |
|
111 |
}) |
|
112 |
.create(); |
|
113 |
} |
|
114 |
return null; |
|
115 |
} |
|
116 |
|
|
117 |
private void setNetworkItemList(ArrayList<NetworkItem> networkItems) { |
|
118 |
if (networkItems == null) { |
|
119 |
networkItems = new ArrayList<NetworkItem>(); |
|
120 |
} |
|
121 |
this.networkItems = new ArrayList<NetworkItem>(); |
|
122 |
String[] networkItemNames = new String[networkItems.size()]; |
|
123 |
|
|
124 |
if (networkItems != null) { |
|
125 |
for (int i = 0; i < networkItems.size(); i++) { |
|
126 |
NetworkItem networkItem = networkItems.get(i); |
|
127 |
this.networkItems.add(i, networkItem); |
|
128 |
networkItemNames[i] = networkItem.getName(); |
|
129 |
} |
|
130 |
} |
|
131 |
|
|
132 |
if (networkItemNames.length == 0) { |
|
133 |
displayNoRulesCell(); |
|
134 |
} else { |
|
135 |
getListView().setDividerHeight(1); // restore divider lines |
|
136 |
setListAdapter(new NetworkItemAdapter()); |
|
137 |
} |
|
138 |
} |
|
139 |
|
|
140 |
private void displayLoadingCell() { |
|
141 |
String a[] = new String[1]; |
|
142 |
a[0] = "Loading..."; |
|
143 |
setListAdapter(new ArrayAdapter<String>(this, R.layout.loadingcell, R.id.loading_label, a)); |
|
144 |
getListView().setTextFilterEnabled(true); |
|
145 |
getListView().setDividerHeight(0); // hide the dividers so it won't look like a list row |
|
146 |
getListView().setItemsCanFocus(false); |
|
147 |
} |
|
148 |
|
|
149 |
private void displayNoRulesCell() { |
|
150 |
String a[] = new String[1]; |
|
151 |
a[0] = "No Rules"; |
|
152 |
setListAdapter(new ArrayAdapter<String>(this, R.layout.norulescell, R.id.no_rules_label, a)); |
|
153 |
getListView().setTextFilterEnabled(true); |
|
154 |
getListView().setDividerHeight(0); // hide the dividers so it won't look like a list row |
|
155 |
getListView().setItemsCanFocus(false); |
|
156 |
} |
|
157 |
|
|
158 |
private void loadNetworkItems() { |
|
159 |
displayLoadingCell(); |
|
160 |
new LoadNetworkItemsTask().execute((Void[]) null); |
|
161 |
} |
|
162 |
|
|
163 |
// * Adapter/ |
|
164 |
class NetworkItemAdapter extends ArrayAdapter<NetworkItem> { |
|
165 |
NetworkItemAdapter() { |
|
166 |
super(AccessControlActivity.this, R.layout.accesscontrolcell, networkItems); |
|
167 |
} |
|
168 |
|
|
169 |
public View getView(int position, View convertView, ViewGroup parent) { |
|
170 |
|
|
171 |
NetworkItem networkItem = networkItems.get(position); |
|
172 |
LayoutInflater inflater = getLayoutInflater(); |
|
173 |
View row = inflater.inflate(R.layout.accesscontrolcell, parent, false); |
|
174 |
|
|
175 |
TextView label = (TextView) row.findViewById(R.id.ip_address_text); |
|
176 |
label.setText(networkItem.getAddress()); |
|
177 |
|
|
178 |
TextView sublabel = (TextView) row.findViewById(R.id.status_text); |
|
179 |
sublabel.setText(networkItem.getType()); |
|
180 |
|
|
181 |
ImageView typeImage = (ImageView) row.findViewById(R.id.rule_type_image); |
|
182 |
int image; |
|
183 |
if(networkItem.getType().equals("ALLOW")){ |
|
184 |
image = R.drawable.allow_rule; |
|
185 |
} else { |
|
186 |
image = R.drawable.deny_rule; |
|
187 |
} |
|
188 |
typeImage.setImageResource(image); |
|
189 |
|
|
190 |
|
|
191 |
return(row); |
|
192 |
} |
|
193 |
} |
|
194 |
|
|
195 |
private class LoadNetworkItemsTask extends AsyncTask<Void, Void, ArrayList<NetworkItem>> { |
|
196 |
private LoadBalancersException exception; |
|
197 |
|
|
198 |
@Override |
|
199 |
protected void onPreExecute(){ |
|
200 |
//set to null so will reload on config changes |
|
201 |
networkItems = null; |
|
202 |
} |
|
203 |
|
|
204 |
@Override |
|
205 |
protected ArrayList<NetworkItem> doInBackground(Void... arg0) { |
|
206 |
ArrayList<NetworkItem> networkItems = null; |
|
207 |
try { |
|
208 |
networkItems = new NetworkItemManager(getContext()).createList(loadBalancer); |
|
209 |
} catch (LoadBalancersException e) { |
|
210 |
exception = e; |
|
211 |
} |
|
212 |
return networkItems; |
|
213 |
} |
|
214 |
|
|
215 |
@Override |
|
216 |
protected void onPostExecute(ArrayList<NetworkItem> result) { |
|
217 |
if (exception != null) { |
|
218 |
showAlert("Error", exception.getMessage()); |
|
219 |
} |
|
220 |
setNetworkItemList(result); |
|
221 |
} |
|
222 |
} |
|
223 |
|
|
224 |
private class DeleteNetworkItemTask extends AsyncTask<Void, Void, HttpBundle> { |
|
225 |
|
|
226 |
private CloudServersException exception; |
|
227 |
private NetworkItem networkItem; |
|
228 |
|
|
229 |
@Override |
|
230 |
//let user know their process has started |
|
231 |
protected void onPreExecute(){ |
|
232 |
networkItem = networkItems.get(lastSelectedRulePosition); |
|
233 |
displayLoadingCell(); |
|
234 |
//set to null so will reload on config change |
|
235 |
networkItems = null; |
|
236 |
} |
|
237 |
@Override |
|
238 |
protected HttpBundle doInBackground(Void... arg0) { |
|
239 |
HttpBundle bundle = null; |
|
240 |
try { |
|
241 |
bundle = new NetworkItemManager(getContext()).delete(loadBalancer, networkItem); |
|
242 |
} catch (CloudServersException e) { |
|
243 |
exception = e; |
|
244 |
} |
|
245 |
return bundle; |
|
246 |
} |
|
247 |
|
|
248 |
@Override |
|
249 |
protected void onPostExecute(HttpBundle bundle) { |
|
250 |
HttpResponse response = bundle.getResponse(); |
|
251 |
if (response != null) { |
|
252 |
int statusCode = response.getStatusLine().getStatusCode(); |
|
253 |
if (statusCode == 202 || statusCode == 200) { |
|
254 |
setResult(Activity.RESULT_OK); |
|
255 |
loadNetworkItems(); |
|
256 |
} else { |
|
257 |
CloudServersException cse = parseCloudServersException(response); |
|
258 |
if ("".equals(cse.getMessage())) { |
|
259 |
showError("There was a problem deleting your rule.", bundle); |
|
260 |
} else { |
|
261 |
showError("There was a problem deleting your rule: " + cse.getMessage(), bundle); |
|
262 |
} |
|
263 |
} |
|
264 |
} else if (exception != null) { |
|
265 |
showError("There was a problem deleting your rule: " + exception.getMessage(), bundle); |
|
266 |
} |
|
267 |
} |
|
268 |
} |
|
269 |
|
|
270 |
|
|
271 |
|
|
272 |
protected void onActivityResult(int requestCode, int resultCode, Intent data){ |
|
273 |
if(requestCode == ADD_RULE && resultCode == RESULT_OK){ |
|
274 |
loadNetworkItems(); |
|
275 |
} |
|
276 |
} |
|
277 |
} |
b/src/com/rackspace/cloud/android/AddAccessRuleActivity.java | ||
---|---|---|
1 |
package com.rackspace.cloud.android; |
|
2 |
|
|
3 |
import java.util.ArrayList; |
|
4 |
import java.util.Arrays; |
|
5 |
import java.util.regex.Matcher; |
|
6 |
import java.util.regex.Pattern; |
|
7 |
|
|
8 |
import org.apache.http.HttpResponse; |
|
9 |
|
|
10 |
import android.app.Activity; |
|
11 |
import android.os.AsyncTask; |
|
12 |
import android.os.Bundle; |
|
13 |
import android.text.Editable; |
|
14 |
import android.text.TextWatcher; |
|
15 |
import android.view.View; |
|
16 |
import android.view.View.OnClickListener; |
|
17 |
import android.widget.AdapterView; |
|
18 |
import android.widget.AdapterView.OnItemSelectedListener; |
|
19 |
import android.widget.ArrayAdapter; |
|
20 |
import android.widget.Button; |
|
21 |
import android.widget.EditText; |
|
22 |
import android.widget.Spinner; |
|
23 |
|
|
24 |
import com.rackspace.cloud.android.R; |
|
25 |
import com.rackspace.cloud.loadbalancer.api.client.LoadBalancer; |
|
26 |
import com.rackspace.cloud.loadbalancer.api.client.NetworkItem; |
|
27 |
import com.rackspace.cloud.loadbalancer.api.client.NetworkItemManager; |
|
28 |
import com.rackspace.cloud.servers.api.client.CloudServersException; |
|
29 |
import com.rackspace.cloud.servers.api.client.http.HttpBundle; |
|
30 |
|
|
31 |
public class AddAccessRuleActivity extends CloudActivity{ |
|
32 |
|
|
33 |
private final String[] ACTIONS = {"Deny", "Allow"}; |
|
34 |
|
|
35 |
private LoadBalancer loadBalancer; |
|
36 |
private String selectedAction; |
|
37 |
private String selectedAddresses; |
|
38 |
|
|
39 |
@Override |
|
40 |
public void onCreate(Bundle savedInstanceState) { |
|
41 |
super.onCreate(savedInstanceState); |
|
42 |
loadBalancer = (LoadBalancer) this.getIntent().getExtras().get("loadBalancer"); |
|
43 |
setContentView(R.layout.addaccessrule); |
|
44 |
restoreState(savedInstanceState); |
|
45 |
} |
|
46 |
|
|
47 |
@Override |
|
48 |
protected void onSaveInstanceState(Bundle outState) { |
|
49 |
super.onSaveInstanceState(outState); |
|
50 |
} |
|
51 |
|
|
52 |
protected void restoreState(Bundle state) { |
|
53 |
super.restoreState(state); |
|
54 |
setupInputs(); |
|
55 |
} |
|
56 |
|
|
57 |
private void setupInputs(){ |
|
58 |
Spinner actionSpinner = (Spinner)findViewById(R.id.rule_action_spinner); |
|
59 |
|
|
60 |
ArrayAdapter<String> actionAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, ACTIONS); |
|
61 |
actionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
62 |
actionSpinner.setAdapter(actionAdapter); |
|
63 |
|
|
64 |
actionSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { |
|
65 |
|
|
66 |
@Override |
|
67 |
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { |
|
68 |
selectedAction = ACTIONS[pos]; |
|
69 |
} |
|
70 |
|
|
71 |
@Override |
|
72 |
public void onNothingSelected(AdapterView<?> arg0) { |
|
73 |
|
|
74 |
} |
|
75 |
|
|
76 |
}); |
|
77 |
|
|
78 |
EditText address = (EditText)findViewById(R.id.rule_address); |
|
79 |
address.addTextChangedListener(new TextWatcher() { |
|
80 |
|
|
81 |
@Override |
|
82 |
public void onTextChanged(CharSequence s, int start, int before, int count) { |
|
83 |
selectedAddresses = s.toString(); |
|
84 |
} |
|
85 |
|
|
86 |
@Override |
|
87 |
public void beforeTextChanged(CharSequence s, int start, int count, |
|
88 |
int after) { |
|
89 |
//do nothing |
|
90 |
} |
|
91 |
|
|
92 |
@Override |
|
93 |
public void afterTextChanged(Editable s) { |
|
94 |
//do nothing |
|
95 |
} |
|
96 |
}); |
|
97 |
|
|
98 |
Button addRule = (Button)findViewById(R.id.add_rule_button); |
|
99 |
addRule.setOnClickListener(new OnClickListener() { |
|
100 |
|
|
101 |
@SuppressWarnings("unchecked") |
|
102 |
@Override |
|
103 |
public void onClick(View v) { |
|
104 |
if(!validAddress(selectedAddresses)){ |
|
105 |
showAlert("Error", "Please enter a valid IP address."); |
|
106 |
} else if(!validAction(selectedAction)) { |
|
107 |
showAlert("Error", "Please select an action type."); |
|
108 |
} else{ |
|
109 |
ArrayList<NetworkItem> networkItems = new ArrayList<NetworkItem>(); |
|
110 |
String[] networkAddresses = selectedAddresses.split(","); |
|
111 |
for(int i = 0; i < networkAddresses.length; i++){ |
|
112 |
NetworkItem networkItem = new NetworkItem(); |
|
113 |
networkItem.setAddress(networkAddresses[i].trim()); |
|
114 |
networkItem.setType(selectedAction); |
|
115 |
networkItems.add(networkItem); |
|
116 |
} |
|
117 |
new AddNetworkItemTask().execute(networkItems); |
|
118 |
} |
|
119 |
} |
|
120 |
}); |
|
121 |
} |
|
122 |
|
|
123 |
//basic ip validation just checks that the string |
|
124 |
//is only composed of letters, numbers, ., : and , |
|
125 |
private static boolean validAddress(String address){ |
|
126 |
//if just white space return false; |
|
127 |
//check regex |
|
128 |
if(address != null && !address.trim().equals("")){ |
|
129 |
Pattern pattern = Pattern.compile("[a-zA-Z0-9.:/, ]+"); |
|
130 |
Matcher match = pattern.matcher(address); |
|
131 |
return match.matches(); |
|
132 |
} else { |
|
133 |
return false; |
|
134 |
} |
|
135 |
} |
|
136 |
|
|
137 |
private Boolean validAction(String action){ |
|
138 |
return action != null && Arrays.asList(ACTIONS).contains(action); |
|
139 |
} |
|
140 |
|
|
141 |
private class AddNetworkItemTask extends AsyncTask<ArrayList<NetworkItem>, Void, HttpBundle> { |
|
142 |
|
|
143 |
private CloudServersException exception; |
|
144 |
|
|
145 |
@Override |
|
146 |
protected void onPreExecute(){ |
|
147 |
showDialog(); |
|
148 |
} |
|
149 |
@Override |
|
150 |
protected HttpBundle doInBackground(ArrayList<NetworkItem>... networkItems) { |
|
151 |
HttpBundle bundle = null; |
|
152 |
try { |
|
153 |
bundle = new NetworkItemManager(getContext()).create(loadBalancer, networkItems[0]); |
|
154 |
} catch (CloudServersException e) { |
|
155 |
exception = e; |
|
156 |
} |
|
157 |
return bundle; |
|
158 |
} |
|
159 |
|
|
160 |
@Override |
|
161 |
protected void onPostExecute(HttpBundle bundle) { |
|
162 |
hideDialog(); |
|
163 |
HttpResponse response = bundle.getResponse(); |
|
164 |
if (response != null) { |
|
165 |
int statusCode = response.getStatusLine().getStatusCode(); |
|
166 |
if (statusCode == 202 || statusCode == 200) { |
|
167 |
setResult(Activity.RESULT_OK); |
|
168 |
finish(); |
|
169 |
} else { |
|
170 |
CloudServersException cse = parseCloudServersException(response); |
|
171 |
if ("".equals(cse.getMessage())) { |
|
172 |
showError("There was a problem creating your rule.", bundle); |
|
173 |
} else { |
|
174 |
showError("There was a problem creating your rule: " + cse.getMessage(), bundle); |
|
175 |
} |
|
176 |
} |
|
177 |
} else if (exception != null) { |
|
178 |
showError("There was a problem creating your rule: " + exception.getMessage(), bundle); |
|
179 |
} |
|
180 |
} |
|
181 |
} |
|
182 |
} |
b/src/com/rackspace/cloud/android/AddAccountActivity.java | ||
---|---|---|
1 |
package com.rackspace.cloud.android; |
|
2 |
|
|
3 |
import android.content.Intent; |
|
4 |
import android.os.Bundle; |
|
5 |
import android.text.method.PasswordTransformationMethod; |
|
6 |
import android.text.method.SingleLineTransformationMethod; |
|
7 |
import android.view.View; |
|
8 |
import android.view.View.OnClickListener; |
|
9 |
import android.widget.AdapterView; |
|
10 |
import android.widget.ArrayAdapter; |
|
11 |
import android.widget.Button; |
|
12 |
import android.widget.CheckBox; |
|
13 |
import android.widget.EditText; |
|
14 |
import android.widget.Spinner; |
|
15 |
|
|
16 |
import com.rackspace.cloud.android.R; |
|
17 |
|
|
18 |
public class AddAccountActivity extends CloudActivity implements OnClickListener{ |
|
19 |
|
|
20 |
private final String[] PROVIDERS = {"Rackspace Cloud (US)", "Rackspace Cloud (UK)","Pithos+", "Pithos+ Dev","Custom"}; |
|
21 |
private EditText usernameText; |
|
22 |
private EditText passwordText; |
|
23 |
private EditText customServer; |
|
24 |
private Spinner providerSpinner; |
|
25 |
private String authServer; |
|
26 |
boolean isHidden; |
|
27 |
|
|
28 |
public void onCreate(Bundle savedInstanceState) { |
|
29 |
super.onCreate(savedInstanceState); |
|
30 |
trackPageView(GoogleAnalytics.PAGE_PROVIDERS); |
|
31 |
setContentView(R.layout.createaccount); |
|
32 |
usernameText = (EditText) findViewById(R.id.username); |
|
33 |
passwordText = (EditText) findViewById(R.id.addaccount_apikey); |
|
34 |
customServer = (EditText) findViewById(R.id.custom_auth_server_edit); |
|
35 |
((Button) findViewById(R.id.submit_new_account)).setOnClickListener(this); |
|
36 |
isHidden = true; |
|
37 |
customServer.setEnabled(false); |
|
38 |
if(savedInstanceState != null) |
|
39 |
isHidden = savedInstanceState.containsKey("isHidden") && savedInstanceState.getBoolean("isHidden"); |
|
40 |
setUpApiText(savedInstanceState); |
|
41 |
setUpCheckBox(); |
|
42 |
loadProviderSpinner(); |
|
43 |
} |
|
44 |
|
|
45 |
protected void onSaveInstanceState(Bundle outState) { |
|
46 |
super.onSaveInstanceState(outState); |
|
47 |
outState.putBoolean("isHidden", isHidden); |
|
48 |
} |
|
49 |
|
|
50 |
//setup the API textedit to be password dots or regular text |
|
51 |
private void setUpApiText(Bundle state){ |
|
52 |
isHidden = true; |
|
53 |
if(state != null) |
|
54 |
isHidden = state.containsKey("isHidden") && state.getBoolean("isHidden"); |
|
55 |
if(isHidden){ |
|
56 |
passwordText.setTransformationMethod(new PasswordTransformationMethod()); |
|
57 |
} |
|
58 |
else{ |
|
59 |
passwordText.setTransformationMethod(new SingleLineTransformationMethod()); |
|
60 |
} |
|
61 |
} |
|
62 |
|
|
63 |
private void setUpCheckBox(){ |
|
64 |
final CheckBox show_clear = (CheckBox) findViewById(R.id.show_clear); |
|
65 |
show_clear.setChecked(!isHidden); |
|
66 |
show_clear.setOnClickListener(new OnClickListener() { |
|
67 |
@Override |
|
68 |
public void onClick(View v) { |
|
69 |
if (((CheckBox) v).isChecked()) { |
|
70 |
passwordText.setTransformationMethod(new SingleLineTransformationMethod()); |
|
71 |
isHidden = false; |
|
72 |
} else { |
|
73 |
passwordText.setTransformationMethod(new PasswordTransformationMethod()); |
|
74 |
isHidden = true; |
|
75 |
} |
|
76 |
passwordText.requestFocus(); |
|
77 |
} |
|
78 |
}); |
|
79 |
} |
|
80 |
|
|
81 |
private void loadProviderSpinner(){ |
|
82 |
//set the auth server default to us |
|
83 |
authServer = "https://auth.api.rackspacecloud.com/v2.0"; |
|
84 |
providerSpinner = (Spinner) findViewById(R.id.provider_spinner); |
|
85 |
ArrayAdapter<String> imageAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, PROVIDERS); |
|
86 |
imageAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
87 |
providerSpinner.setAdapter(imageAdapter); |
|
88 |
providerSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){ |
|
89 |
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { |
|
90 |
if(pos == 0){ |
|
91 |
authServer = Preferences.COUNTRY_US_AUTH_SERVER_V2; |
|
92 |
customServer.setEnabled(false); |
|
93 |
} |
|
94 |
else if(pos == 1){ |
|
95 |
authServer = Preferences.COUNTRY_UK_AUTH_SERVER_V2; |
|
96 |
customServer.setEnabled(false); |
|
97 |
} |
|
98 |
else if(pos == 2){ |
|
99 |
authServer = Preferences.PITHOS_SERVER; |
|
100 |
customServer.setEnabled(false); |
|
101 |
} |
|
102 |
else if(pos == 3){ |
|
103 |
authServer = Preferences.PITHOS_DEV_SERVER; |
|
104 |
customServer.setEnabled(false); |
|
105 |
} |
|
106 |
else{ |
|
107 |
customServer.setEnabled(true); |
|
108 |
} |
|
109 |
} |
|
110 |
public void onNothingSelected(AdapterView<?> parent) { |
|
111 |
} |
|
112 |
}); |
|
113 |
} |
|
114 |
|
|
115 |
public void onClick(View arg0) { |
|
116 |
|
|
117 |
if (hasValidInput()) { |
|
118 |
//showActivityIndicators(); |
|
119 |
Intent result = new Intent(); |
|
120 |
Bundle b = new Bundle(); |
|
121 |
b.putString("username", usernameText.getText().toString()); |
|
122 |
b.putString("apiKey", passwordText.getText().toString()); |
|
123 |
b.putString("server", getAuthServer()); |
|
124 |
result.putExtra("accountInfo", b); |
|
125 |
setResult(RESULT_OK, result); |
|
126 |
finish(); |
|
127 |
} else { |
|
128 |
showAlert("Required Fields Missing", "Username and API Key are required."); |
|
129 |
} |
|
130 |
|
|
131 |
} |
|
132 |
|
|
133 |
private String getAuthServer(){ |
|
134 |
if(customServer.isEnabled()){ |
|
135 |
authServer = customServer.getText().toString(); |
|
136 |
} |
|
137 |
return authServer; |
|
138 |
} |
|
139 |
|
|
140 |
private boolean hasValidInput() { |
|
141 |
String username = usernameText.getText().toString(); |
|
142 |
String apiKey = passwordText.getText().toString(); |
|
143 |
return !"".equals(username) && !"".equals(apiKey); |
|
144 |
} |
|
145 |
|
|
146 |
} |
b/src/com/rackspace/cloud/android/AddContainerActivity.java | ||
---|---|---|
1 |
package com.rackspace.cloud.android; |
|
2 |
|
|
3 |
import org.apache.http.HttpResponse; |
|
4 |
|
|
5 |
import android.app.Activity; |
|
6 |
import android.os.AsyncTask; |
|
7 |
import android.os.Bundle; |
|
8 |
import android.view.View; |
|
9 |
import android.view.View.OnClickListener; |
|
10 |
import android.widget.Button; |
|
11 |
import android.widget.EditText; |
|
12 |
|
|
13 |
import com.rackspace.cloud.android.R; |
|
14 |
import com.rackspace.cloud.files.api.client.ContainerManager; |
|
15 |
import com.rackspace.cloud.servers.api.client.CloudServersException; |
|
16 |
import com.rackspace.cloud.servers.api.client.http.HttpBundle; |
|
17 |
/** |
|
18 |
* |
|
19 |
* @author Phillip Toohill |
|
20 |
* |
|
21 |
*/ |
|
22 |
public class AddContainerActivity extends CloudActivity implements OnClickListener { |
|
23 |
|
|
24 |
private EditText containerName; |
|
25 |
|
|
26 |
/** Called when the activity is first created. */ |
|
27 |
@Override |
|
28 |
public void onCreate(Bundle savedInstanceState) { |
|
29 |
super.onCreate(savedInstanceState); |
|
30 |
trackPageView(GoogleAnalytics.PAGE_ADD_CONTAINER); |
|
31 |
setContentView(R.layout.createcontainer); |
|
32 |
restoreState(savedInstanceState); |
|
33 |
} |
|
34 |
|
|
35 |
protected void restoreState(Bundle state){ |
|
36 |
super.restoreState(state); |
|
37 |
containerName = (EditText) findViewById(R.id.container_name); |
|
38 |
((Button) findViewById(R.id.save_button)).setOnClickListener(this); |
|
39 |
} |
|
40 |
|
|
41 |
public void onClick(View arg0) { |
|
42 |
if ("".equals(containerName.getText().toString())) { |
|
43 |
showAlert("Required Fields Missing", " Container name is required."); |
|
44 |
} else { |
|
45 |
trackEvent(GoogleAnalytics.CATEGORY_CONTAINER, GoogleAnalytics.EVENT_CREATE, "", -1); |
|
46 |
new CreateContainerTask().execute((Void[]) null); |
|
47 |
} |
|
48 |
} |
|
49 |
|
|
50 |
private class CreateContainerTask extends AsyncTask<Void, Void, HttpBundle> { |
|
51 |
private CloudServersException exception; |
|
52 |
|
|
53 |
protected void onPreExecute(){ |
|
54 |
showDialog(); |
|
55 |
} |
|
56 |
|
|
57 |
@Override |
|
58 |
protected HttpBundle doInBackground(Void... arg0) { |
|
59 |
HttpBundle bundle = null; |
|
60 |
try { |
|
61 |
bundle = (new ContainerManager(getContext())).create(containerName.getText()); |
|
62 |
} catch (CloudServersException e) { |
|
63 |
exception = e; |
|
64 |
} |
|
65 |
return bundle; |
|
66 |
} |
|
67 |
|
|
68 |
@Override |
|
69 |
protected void onPostExecute(HttpBundle bundle) { |
|
70 |
hideDialog(); |
|
71 |
HttpResponse response = bundle.getResponse(); |
|
72 |
if (response != null) { |
|
73 |
int statusCode = response.getStatusLine().getStatusCode(); |
|
74 |
if (statusCode == 201) { |
|
75 |
setResult(Activity.RESULT_OK); |
|
76 |
finish(); |
|
77 |
} else { |
|
78 |
CloudServersException cse = parseCloudServersException(response); |
|
79 |
if ("".equals(cse.getMessage())) { |
|
80 |
showError("There was a problem creating your container.", bundle); |
|
81 |
} else { |
|
82 |
showError("There was a problem creating your container: " + cse.getMessage() + " See details for more information.", bundle); |
|
83 |
} |
|
84 |
} |
|
85 |
} else if (exception != null) { |
|
86 |
showError("There was a problem creating your container: " + exception.getMessage()+" See details for more information.", bundle); |
|
87 |
} |
|
88 |
finish(); |
|
89 |
} |
|
90 |
} |
|
91 |
|
|
92 |
|
|
93 |
|
|
94 |
} |
b/src/com/rackspace/cloud/android/AddExternalNodeActivity.java | ||
---|---|---|
1 |
package com.rackspace.cloud.android; |
|
2 |
|
|
3 |
import java.util.regex.Matcher; |
|
4 |
import java.util.regex.Pattern; |
|
5 |
|
|
6 |
import android.content.Intent; |
|
7 |
import android.os.Bundle; |
|
8 |
import android.util.Log; |
|
9 |
import android.view.View; |
|
10 |
import android.view.View.OnClickListener; |
|
11 |
import android.view.Window; |
|
12 |
import android.widget.AdapterView; |
|
13 |
import android.widget.AdapterView.OnItemSelectedListener; |
|
14 |
import android.widget.ArrayAdapter; |
|
15 |
import android.widget.Button; |
|
16 |
import android.widget.EditText; |
|
17 |
import android.widget.Spinner; |
|
18 |
import android.widget.TextView; |
|
19 |
|
|
20 |
import com.rackspace.cloud.android.R; |
|
21 |
import com.rackspace.cloud.loadbalancer.api.client.Node; |
|
22 |
|
|
23 |
public class AddExternalNodeActivity extends CloudActivity { |
|
24 |
|
|
25 |
private final String[] CONDITIONS = {"Enabled", "Disabled", "Draining"}; |
|
26 |
private String selectedPort; |
|
27 |
private String selectedIp; |
|
28 |
private String selectedWeight; |
|
29 |
private boolean weighted; |
|
30 |
private String selectedCondition; |
|
31 |
private Spinner conditionSpinner; |
|
32 |
private EditText ipAddress; |
|
33 |
private EditText weightText; |
|
34 |
private Node node; |
|
35 |
|
|
36 |
public void onCreate(Bundle savedInstanceState) { |
|
37 |
super.onCreate(savedInstanceState); |
|
38 |
requestWindowFeature(Window.FEATURE_NO_TITLE); |
|
39 |
setContentView(R.layout.addexternalnode); |
|
40 |
weighted = (Boolean) this.getIntent().getExtras().get("weighted"); |
|
41 |
node = (Node) this.getIntent().getExtras().get("node"); |
|
42 |
selectedPort = (String) this.getIntent().getExtras().get("loadBalancerPort"); |
|
43 |
restoreState(savedInstanceState); |
|
44 |
} |
|
45 |
|
|
46 |
protected void restoreState(Bundle state) { |
|
47 |
super.restoreState(state); |
|
48 |
setupInputs(); |
|
49 |
} |
|
50 |
|
|
51 |
private void setupInputs(){ |
|
52 |
|
|
53 |
ipAddress = (EditText) findViewById(R.id.ip_address); |
|
54 |
|
|
55 |
weightText = (EditText) findViewById(R.id.node_weight_text); |
|
56 |
|
|
57 |
//if algorithm is not weighted then then node's weight will be null |
|
58 |
if(!weighted){ |
|
59 |
TextView weightLabel = (TextView) findViewById(R.id.node_weight_label); |
|
60 |
weightLabel.setVisibility(View.GONE); |
|
61 |
weightText.setVisibility(View.GONE); |
|
62 |
} |
|
63 |
|
|
64 |
loadConditionSpinner(); |
|
65 |
setUpButton(); |
|
66 |
|
|
67 |
if(node != null){ |
|
68 |
ipAddress.setText(node.getAddress()); |
|
69 |
weightText.setText(node.getWeight()); |
|
70 |
((EditText)findViewById(R.id.node_port_text)).setText(node.getPort()); |
|
71 |
conditionSpinner.setSelection(getLocation(CONDITIONS, node.getCondition())); |
|
72 |
} else { |
|
73 |
Log.d("info", "node was null"); |
|
74 |
((EditText)findViewById(R.id.node_port_text)).setText(selectedPort); |
|
75 |
} |
|
76 |
} |
|
77 |
|
|
78 |
private int getLocation(Object[] objects, Object object){ |
|
79 |
for(int i = 0; i < objects.length; i++){ |
|
80 |
if(object.equals(objects[i])){ |
|
81 |
return i; |
|
82 |
} |
|
83 |
} |
|
84 |
return 0; |
|
85 |
} |
|
86 |
|
|
87 |
private void setUpButton(){ |
|
88 |
Button submit = (Button) findViewById(R.id.add_node_button); |
|
89 |
submit.setOnClickListener(new OnClickListener() { |
|
90 |
|
|
91 |
@Override |
|
92 |
public void onClick(View v) { |
|
93 |
selectedIp = ipAddress.getText().toString().trim(); |
|
94 |
selectedPort = ((EditText)findViewById(R.id.node_port_text)).getText().toString().trim(); |
|
95 |
selectedWeight = weightText.getText().toString().trim(); |
|
96 |
if(!validPort(selectedPort)){ |
|
97 |
showAlert("Error", "Must have a protocol port number that is between 1 and 65535."); |
|
98 |
} else if(!(weightText.getVisibility() == View.GONE || (weightText.getVisibility() != View.GONE && validWeight(selectedWeight)))){ |
|
99 |
showAlert("Error", "Weight must be between 1 and 100."); |
|
100 |
} else if(selectedIp.equals("")){ |
|
101 |
//TODO use regex to validate the ip for IPV4 and IPV6 |
|
102 |
showAlert("Error", "Enter an IP Address"); |
|
103 |
} else if(!validIp(selectedIp)) { |
|
104 |
showAlert("Error", "Enter a valid IP Address"); |
|
105 |
} else { |
|
106 |
Intent data = new Intent(); |
|
107 |
data.putExtra("nodeIp", selectedIp); |
|
108 |
data.putExtra("nodePort", selectedPort); |
|
109 |
data.putExtra("nodeCondition", selectedCondition); |
|
110 |
data.putExtra("nodeWeight", selectedWeight); |
|
111 |
setResult(RESULT_OK, data); |
|
112 |
finish(); |
|
113 |
} |
|
114 |
|
|
115 |
} |
|
116 |
}); |
|
117 |
} |
|
118 |
|
|
119 |
private void loadConditionSpinner(){ |
|
120 |
conditionSpinner = (Spinner) findViewById(R.id.node_condition_spinner); |
|
121 |
|
|
122 |
ArrayAdapter<String> conditionAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, CONDITIONS); |
|
123 |
conditionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
124 |
conditionSpinner.setAdapter(conditionAdapter); |
|
125 |
|
|
126 |
conditionSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { |
|
127 |
|
|
128 |
@Override |
|
129 |
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { |
|
130 |
selectedCondition = CONDITIONS[pos]; |
|
131 |
} |
|
132 |
|
|
133 |
@Override |
|
134 |
public void onNothingSelected(AdapterView<?> arg0) { |
|
135 |
|
|
136 |
} |
|
137 |
|
|
138 |
}); |
|
139 |
} |
|
140 |
|
|
141 |
//basic ip validation just checks that the string |
|
142 |
//is only composed of letters, numbers, ., : |
|
143 |
private static boolean validIp(String ip){ |
|
144 |
//Enter regex |
|
145 |
if(ip != null){ |
|
146 |
Pattern pattern = Pattern.compile("[a-zA-Z0-9.:]+"); |
|
147 |
Matcher match = pattern.matcher(ip); |
|
148 |
return match.matches(); |
|
149 |
} else { |
|
150 |
return false; |
|
151 |
} |
|
152 |
} |
|
153 |
|
|
154 |
private boolean validPort(String port){ |
|
155 |
boolean result; |
|
156 |
try{ |
|
157 |
result = !port.equals("") && Integer.valueOf(port) > 0 && Integer.valueOf(port) < 65536; |
|
158 |
} catch (NumberFormatException e) { |
|
159 |
result = false; |
|
160 |
} |
|
161 |
return result; |
|
162 |
} |
|
163 |
|
|
164 |
private Boolean validWeight(String weight){ |
|
165 |
if(weight.equals("")){ |
|
166 |
return false; |
|
167 |
} |
|
168 |
else{ |
|
169 |
int w; |
|
170 |
try{ |
|
171 |
w = Integer.valueOf(weight); |
|
172 |
} catch (NumberFormatException e){ |
|
173 |
return false; |
|
174 |
} |
|
175 |
return w >= 1 && w <= 100 ; |
|
176 |
} |
|
177 |
} |
|
178 |
|
|
179 |
public void onBackPressed(){ |
|
180 |
setResult(RESULT_CANCELED); |
|
181 |
finish(); |
|
182 |
} |
|
183 |
|
|
184 |
} |
|
185 |
|
b/src/com/rackspace/cloud/android/AddFileActivity.java | ||
---|---|---|
1 |
package com.rackspace.cloud.android; |
|
2 |
|
|
3 |
import org.apache.http.HttpResponse; |
|
4 |
|
|
5 |
import android.app.Activity; |
|
6 |
import android.os.AsyncTask; |
|
7 |
import android.os.Bundle; |
|
8 |
import android.view.View; |
|
9 |
import android.view.View.OnClickListener; |
|
10 |
import android.widget.Button; |
|
11 |
import android.widget.EditText; |
|
12 |
|
|
13 |
import com.rackspace.cloud.android.R; |
|
14 |
import com.rackspace.cloud.files.api.client.ContainerObjectManager; |
|
15 |
import com.rackspace.cloud.servers.api.client.CloudServersException; |
|
16 |
import com.rackspace.cloud.servers.api.client.http.HttpBundle; |
|
17 |
|
|
18 |
public class AddFileActivity extends CloudActivity implements OnClickListener{ |
|
19 |
|
|
20 |
private EditText fileName; |
|
21 |
private EditText contents; |
|
22 |
private String containerName; |
|
23 |
private String path; |
|
24 |
|
|
25 |
/** Called when the activity is first created. */ |
|
26 |
@Override |
|
27 |
public void onCreate(Bundle savedInstanceState) { |
|
28 |
super.onCreate(savedInstanceState); |
|
29 |
trackPageView(GoogleAnalytics.PAGE_ADD_OBJECT); |
|
30 |
setContentView(R.layout.addtextfile); |
|
31 |
restoreState(savedInstanceState); |
|
32 |
} |
|
33 |
|
|
34 |
protected void restoreState(Bundle state){ |
|
35 |
super.restoreState(state); |
|
36 |
containerName = (String) this.getIntent().getExtras().get("Cname"); |
|
37 |
path = (String) this.getIntent().getExtras().get("curPath"); |
|
38 |
setUpInputs(); |
|
39 |
} |
|
40 |
|
|
41 |
@Override |
|
42 |
protected void onSaveInstanceState(Bundle outState) { |
|
43 |
super.onSaveInstanceState(outState); |
|
44 |
} |
|
45 |
|
|
46 |
private void setUpInputs(){ |
|
47 |
((Button) findViewById(R.id.new_file_button)).setOnClickListener(this); |
|
48 |
fileName = ((EditText)findViewById(R.id.file_name_text)); |
|
49 |
fileName.append(".txt"); |
|
50 |
contents = ((EditText)findViewById(R.id.new_file_text)); |
|
51 |
} |
|
52 |
|
|
53 |
public void onClick(View arg0) { |
|
54 |
if ("".equals(fileName.getText().toString())) { |
|
55 |
showAlert("Required Fields Missing", " File name is required."); |
|
56 |
} else { |
|
57 |
trackEvent(GoogleAnalytics.CATEGORY_FILE, GoogleAnalytics.EVENT_CREATE, "", -1); |
|
58 |
new SaveFileTask().execute((Void[]) null); |
|
59 |
} |
|
60 |
} |
|
61 |
|
|
62 |
private class SaveFileTask extends AsyncTask<Void, Void, HttpBundle> { |
|
63 |
private CloudServersException exception; |
|
64 |
|
|
65 |
protected void onPreExecute(){ |
|
66 |
showDialog(); |
|
67 |
} |
|
68 |
|
|
69 |
@Override |
|
70 |
protected HttpBundle doInBackground(Void... arg0) { |
|
71 |
HttpBundle bundle = null; |
|
72 |
try { |
|
73 |
bundle = (new ContainerObjectManager(getContext())).addObject(containerName, path, fileName.getText().toString(), "text/plain", contents.getText().toString()); |
|
74 |
} catch (CloudServersException e) { |
|
75 |
exception = e; |
|
76 |
} |
|
77 |
return bundle; |
|
78 |
} |
|
79 |
|
|
80 |
@Override |
|
81 |
protected void onPostExecute(HttpBundle bundle) { |
|
82 |
hideDialog(); |
|
83 |
HttpResponse response = bundle.getResponse(); |
|
84 |
if (response != null) { |
|
85 |
int statusCode = response.getStatusLine().getStatusCode(); |
|
86 |
if (statusCode == 201) { |
|
87 |
setResult(Activity.RESULT_OK); |
|
88 |
finish(); |
|
89 |
} else { |
|
90 |
CloudServersException cse = parseCloudServersException(response); |
|
91 |
if ("".equals(cse.getMessage())) { |
|
92 |
showError("There was a problem creating your file.", bundle); |
|
93 |
} else { |
|
94 |
showError("There was a problem creating your file: " + cse.getMessage() + " See details for more information", bundle); |
|
95 |
} |
|
96 |
} |
|
97 |
} else if (exception != null) { |
|
98 |
showError("There was a problem creating your file: " + exception.getMessage()+ " See details for more information", bundle); |
|
99 |
} |
|
100 |
} |
|
101 |
} |
|
102 |
} |
b/src/com/rackspace/cloud/android/AddLoadBalancerActivity.java | ||
---|---|---|
1 |
package com.rackspace.cloud.android; |
|
2 |
|
|
3 |
import java.util.ArrayList; |
|
4 |
|
|
5 |
import org.apache.http.HttpResponse; |
|
6 |
|
|
7 |
import android.app.Activity; |
|
8 |
import android.content.Intent; |
|
9 |
import android.os.AsyncTask; |
|
10 |
import android.os.Bundle; |
|
11 |
import android.text.Editable; |
|
12 |
import android.text.TextWatcher; |
|
13 |
import android.util.Log; |
|
14 |
import android.view.View; |
|
15 |
import android.view.View.OnClickListener; |
|
16 |
import android.widget.AdapterView; |
|
17 |
import android.widget.AdapterView.OnItemSelectedListener; |
|
18 |
import android.widget.ArrayAdapter; |
|
19 |
import android.widget.Button; |
|
20 |
import android.widget.EditText; |
|
21 |
import android.widget.Spinner; |
|
22 |
import android.widget.TableRow; |
|
23 |
|
|
24 |
import com.rackspace.cloud.android.R; |
|
25 |
import com.rackspace.cloud.loadbalancer.api.client.Algorithm; |
|
26 |
import com.rackspace.cloud.loadbalancer.api.client.LoadBalancer; |
|
27 |
import com.rackspace.cloud.loadbalancer.api.client.LoadBalancerManager; |
|
28 |
import com.rackspace.cloud.loadbalancer.api.client.Node; |
|
29 |
import com.rackspace.cloud.loadbalancer.api.client.Protocol; |
|
30 |
import com.rackspace.cloud.loadbalancer.api.client.VirtualIp; |
|
31 |
import com.rackspace.cloud.servers.api.client.Account; |
|
32 |
import com.rackspace.cloud.servers.api.client.CloudServersException; |
|
33 |
import com.rackspace.cloud.servers.api.client.Server; |
|
34 |
import com.rackspace.cloud.servers.api.client.http.HttpBundle; |
|
35 |
|
|
36 |
public class AddLoadBalancerActivity extends CloudActivity implements OnItemSelectedListener { |
|
37 |
|
|
38 |
private static final String[] VIP_TYPES = {"Public", "ServiceNet", "Shared"}; |
|
39 |
|
|
40 |
private static final int ADD_NODES_ACTIVITY_CODE = 165; |
|
41 |
private static final int SHARED_VIP_ACTIVITY_CODE = 235; |
|
42 |
|
|
43 |
private ArrayList<Node> nodes; |
|
44 |
private ArrayList<Server> possibleNodes; |
|
45 |
private LoadBalancer loadBalancer; |
|
46 |
private Protocol[] protocols; |
|
47 |
private Protocol selectedProtocol; |
|
48 |
private Algorithm[] algorithms; |
|
49 |
private Algorithm selectedAlgorithm; |
|
50 |
private VirtualIp selectedVip; |
|
51 |
private EditText portEditText; |
|
52 |
private Spinner protocolSpinner; |
|
53 |
private Spinner protocolSubSpinner; |
|
54 |
private Spinner algorithmSpinner; |
|
55 |
private Spinner vipSpinner; |
|
56 |
private Spinner regionSpinner; |
|
57 |
private Button selectVipButton; |
|
58 |
private Button selectNodesButton; |
|
59 |
private String selectedVipType; |
|
60 |
private String selectedRegion; |
|
61 |
private String selectedName; |
|
62 |
private String selectedPort; |
|
63 |
|
|
64 |
@Override |
|
65 |
public void onCreate(Bundle savedInstanceState) { |
|
66 |
super.onCreate(savedInstanceState); |
|
67 |
trackPageView(GoogleAnalytics.PAGE_ADD_LOADBALANCER); |
|
68 |
setContentView(R.layout.view_add_loadbalancer); |
|
69 |
restoreState(savedInstanceState); |
|
70 |
} |
|
71 |
|
|
72 |
@SuppressWarnings("unchecked") |
|
73 |
protected void restoreState(Bundle state) { |
|
74 |
super.restoreState(state); |
|
75 |
|
|
76 |
if(state != null && state.containsKey("nodes")){ |
|
77 |
nodes = (ArrayList<Node>) state.getSerializable("nodes"); |
|
78 |
} |
|
79 |
else{ |
|
80 |
nodes = new ArrayList<Node>(); |
|
81 |
} |
|
82 |
|
|
83 |
if(state != null && state.containsKey("possibleNodes")){ |
|
84 |
possibleNodes = (ArrayList<Server>) state.getSerializable("possibleNodes"); |
|
85 |
} |
|
86 |
else{ |
|
87 |
possibleNodes = new ArrayList<Server>(); |
|
88 |
} |
|
89 |
|
|
90 |
if(state != null && state.containsKey("selectedVip")){ |
|
91 |
selectedVip = (VirtualIp) state.getSerializable("selectedVip"); |
|
92 |
} |
|
93 |
|
|
94 |
setupText(); |
|
95 |
loadProtocolSpinner(); |
|
96 |
loadProtocolSubSpinner(); |
|
97 |
loadAlgorithmSpinner(); |
|
98 |
loadVipSpinner(); |
|
99 |
loadRegionSpinner(); |
|
100 |
setUpButtons(); |
|
101 |
} |
|
102 |
|
|
103 |
@Override |
|
104 |
protected void onSaveInstanceState(Bundle outState) { |
|
105 |
super.onSaveInstanceState(outState); |
|
106 |
outState.putSerializable("nodes", nodes); |
|
107 |
outState.putSerializable("possibleNodes", possibleNodes); |
|
108 |
outState.putSerializable("selectedVip", selectedVip); |
|
109 |
} |
|
110 |
|
|
111 |
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { |
|
112 |
if (parent == protocolSpinner) { |
|
113 |
TableRow customProtocol = (TableRow)findViewById(R.id.custom_protocol_row); |
|
114 |
if(position < protocols.length){ |
|
115 |
selectedProtocol = protocols[position]; |
|
116 |
selectedPort = protocols[position].getDefaultPort(); |
|
117 |
customProtocol.setVisibility(View.GONE); |
|
118 |
} else { |
|
119 |
customProtocol.setVisibility(View.VISIBLE); |
|
120 |
} |
|
121 |
updateVipIndicatorLight(); |
|
122 |
} else if (parent == algorithmSpinner){ |
|
123 |
selectedAlgorithm = algorithms[position]; |
|
124 |
} else if (parent == vipSpinner){ |
|
125 |
selectedVipType = VIP_TYPES[position]; |
|
126 |
if(VIP_TYPES[position].equals("Shared")){ |
|
127 |
((TableRow) findViewById(R.id.select_vip_layout)).setVisibility(View.VISIBLE); |
|
128 |
} else { |
|
129 |
((TableRow) findViewById(R.id.select_vip_layout)).setVisibility(View.GONE); |
|
130 |
} |
|
131 |
updateVipIndicatorLight(); |
|
132 |
} else if (parent == regionSpinner){ |
|
133 |
selectedRegion = Account.getAccount().getLoadBalancerRegions()[position]; |
|
134 |
updateVipIndicatorLight(); |
|
135 |
} else if (parent == protocolSubSpinner){ |
|
136 |
selectedProtocol = protocols[position]; |
|
137 |
updateVipIndicatorLight(); |
|
138 |
} |
|
139 |
} |
|
140 |
|
|
141 |
public void onNothingSelected(AdapterView<?> parent) { |
|
142 |
|
|
143 |
} |
|
144 |
|
|
145 |
private void setUpButtons(){ |
|
146 |
selectVipButton = (Button) findViewById(R.id.selected_shared_vip); |
|
147 |
updateVipIndicatorLight(); |
|
148 |
selectVipButton.setOnClickListener(new OnClickListener() { |
|
149 |
@Override |
|
150 |
public void onClick(View v) { |
|
151 |
Intent viewIntent = new Intent(getApplicationContext(), SharedVipActivity.class); |
|
152 |
viewIntent.putExtra("loadBalancerPort", selectedPort); |
|
153 |
viewIntent.putExtra("loadBalancerRegion", selectedRegion); |
|
154 |
viewIntent.putExtra("selectedVip", selectedVip); |
|
155 |
startActivityForResult(viewIntent, SHARED_VIP_ACTIVITY_CODE); |
|
156 |
} |
|
157 |
}); |
|
158 |
((TableRow) findViewById(R.id.select_vip_layout)).setVisibility(View.GONE); |
|
159 |
|
|
160 |
selectNodesButton = (Button) findViewById(R.id.add_nodes_button); |
|
161 |
updateNodesIndicatorLight(); |
|
162 |
selectNodesButton.setOnClickListener(new OnClickListener() { |
|
163 |
@Override |
|
164 |
public void onClick(View v) { |
|
165 |
Intent viewIntent = new Intent(getApplicationContext(), AddNodesActivity.class); |
|
166 |
viewIntent.putExtra("nodes", nodes); |
|
167 |
if(validPort(selectedPort)){ |
|
168 |
viewIntent.putExtra("loadBalancerPort", selectedPort); |
|
169 |
} |
|
170 |
viewIntent.putExtra("possibleNodes", possibleNodes); |
|
171 |
startActivityForResult(viewIntent, ADD_NODES_ACTIVITY_CODE); |
|
172 |
} |
|
173 |
}); |
|
174 |
|
|
175 |
Button addLoadBalancer = (Button) findViewById(R.id.add_lb_button); |
|
176 |
addLoadBalancer.setOnClickListener(new OnClickListener() { |
|
177 |
|
|
178 |
@Override |
|
179 |
public void onClick(View v) { |
|
180 |
selectedName = ((EditText)findViewById(R.id.edit_lb_name_text)).getText().toString(); |
|
181 |
//selectedPort = ((EditText)findViewById(R.id.edit_port_text)).getText().toString(); |
|
182 |
if(!validName()){ |
|
183 |
showAlert("Error", "Load balancer name cannot be blank."); |
|
184 |
} else if(!validPort(selectedPort)){ |
|
185 |
showAlert("Error", "Must have a protocol port number that is between 1 and 65535."); |
|
186 |
} else if(!validVip()){ |
|
187 |
showAlert("Error", "Please select a valid Virtual IP."); |
|
188 |
} else if(!validNodes()){ |
|
189 |
showAlert("Error", "You must select at least one enabled cloud server or add and enable at least one external node."); |
|
190 |
} else { |
|
191 |
loadBalancer = new LoadBalancer(); |
|
192 |
loadBalancer.setName(selectedName); |
|
193 |
loadBalancer.setProtocol(selectedProtocol.getName()); |
|
194 |
loadBalancer.setPort(selectedPort); |
|
195 |
loadBalancer.setVirtualIpType(selectedVipType); |
|
196 |
loadBalancer.setAlgorithm(selectedAlgorithm.getName()); |
|
197 |
loadBalancer.setRegion(selectedRegion); |
|
198 |
loadBalancer.setNodes(nodes); |
|
199 |
if(selectedVip != null){ |
|
200 |
ArrayList<VirtualIp> vips = new ArrayList<VirtualIp>(); |
|
201 |
vips.add(selectedVip); |
|
202 |
loadBalancer.setVirtualIps(vips); |
|
203 |
} |
|
204 |
trackEvent(GoogleAnalytics.CATEGORY_LOAD_BALANCER, GoogleAnalytics.EVENT_CREATE, "", -1); |
|
205 |
new AddLoadBalancerTask().execute(); |
|
206 |
Log.d("info", "the port is " + selectedPort); |
|
207 |
} |
|
208 |
} |
|
209 |
}); |
|
210 |
} |
|
211 |
|
|
212 |
private boolean validName(){ |
|
213 |
return !selectedName.equals(""); |
|
214 |
} |
|
215 |
|
|
216 |
private boolean validPort(String selectedPort){ |
|
217 |
boolean result; |
|
218 |
try{ |
|
219 |
result = !selectedPort.equals("") && Integer.valueOf(selectedPort) > 0 && Integer.valueOf(selectedPort) < 65536; |
|
220 |
} catch (NumberFormatException e){ |
|
221 |
result = false; |
|
222 |
} |
|
223 |
return result; |
|
224 |
} |
|
225 |
|
|
226 |
private boolean validNodes(){ |
|
227 |
boolean exist = nodes != null && nodes.size() > 0; |
|
228 |
boolean enabled = false; |
|
229 |
for(Node n: nodes){ |
|
230 |
enabled = enabled || n.getCondition().equalsIgnoreCase("enabled"); |
|
231 |
} |
|
232 |
return exist && enabled; |
|
233 |
} |
|
234 |
|
|
235 |
private boolean validVip(){ |
|
236 |
/* |
|
237 |
* assign selectedVipType to the |
|
238 |
* first value in the list, the default |
|
239 |
* if its null |
|
240 |
*/ |
|
241 |
if(selectedVipType == null){ |
|
242 |
selectedVipType = VIP_TYPES[0]; |
|
243 |
} |
|
244 |
return !selectedVipType.equalsIgnoreCase("Shared") |
|
245 |
||(selectedVip != null && !selectedVip.getLoadBalancer().getPort().equals(selectedPort) |
|
246 |
&& selectedVip.getLoadBalancer().getRegion().equals(selectedRegion)); |
|
247 |
} |
|
248 |
|
|
249 |
private void updateNodesIndicatorLight(){ |
|
250 |
if(validNodes()){ |
|
251 |
selectNodesButton.setCompoundDrawablesWithIntrinsicBounds(0,0,0,0); |
|
252 |
} else { |
|
253 |
selectNodesButton.setCompoundDrawablesWithIntrinsicBounds(0,0,R.drawable.ic_notification_overlay,0); |
|
254 |
} |
|
255 |
} |
|
256 |
|
|
257 |
private void updateVipIndicatorLight(){ |
|
258 |
if(validVip()){ |
|
259 |
selectVipButton.setCompoundDrawablesWithIntrinsicBounds(0,0,0,0); |
|
260 |
} else { |
|
261 |
selectVipButton.setCompoundDrawablesWithIntrinsicBounds(0,0,R.drawable.ic_notification_overlay,0); |
|
262 |
} |
|
263 |
} |
|
264 |
|
|
265 |
private void setupText(){ |
|
266 |
portEditText = (EditText)findViewById(R.id.edit_port_text); |
|
267 |
portEditText.addTextChangedListener(new TextWatcher() { |
|
268 |
|
|
269 |
@Override |
|
270 |
public void onTextChanged(CharSequence s, int start, int before, int count) { |
|
271 |
selectedPort = s.toString(); |
|
272 |
updateVipIndicatorLight(); |
|
273 |
} |
|
274 |
@Override |
|
275 |
public void beforeTextChanged(CharSequence s, int start, int count, |
|
276 |
int after) { |
|
277 |
// do nothing |
|
278 |
} |
|
279 |
@Override |
|
280 |
public void afterTextChanged(Editable s) { |
|
281 |
// do nothing |
|
282 |
} |
|
283 |
}); |
|
284 |
} |
|
285 |
|
|
286 |
private void loadRegionSpinner() { |
|
287 |
regionSpinner = (Spinner) findViewById(R.id.edit_region_spinner); |
|
288 |
regionSpinner.setOnItemSelectedListener(this); |
|
289 |
|
|
290 |
ArrayAdapter<String> regionAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, |
|
291 |
Account.getAccount().getLoadBalancerRegions()); |
|
292 |
regionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
293 |
regionSpinner.setAdapter(regionAdapter); |
|
294 |
} |
|
295 |
|
|
296 |
private void loadVipSpinner() { |
|
297 |
vipSpinner = (Spinner) findViewById(R.id.edit_vip_spinner); |
|
298 |
vipSpinner.setOnItemSelectedListener(this); |
|
299 |
|
|
300 |
ArrayAdapter<String> vipAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, VIP_TYPES); |
|
301 |
vipAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
302 |
vipSpinner.setAdapter(vipAdapter); |
|
303 |
} |
|
304 |
|
|
305 |
private void loadProtocolSpinner() { |
|
306 |
protocolSpinner = (Spinner) findViewById(R.id.edit_protocol_spinner); |
|
307 |
protocolSpinner.setOnItemSelectedListener(this); |
|
308 |
String protocolNames[] = new String[Protocol.getProtocols().size() + 1]; |
|
309 |
protocols = new Protocol[Protocol.getProtocols().size()]; |
|
310 |
|
|
311 |
int httpIndex = 0; |
|
312 |
for(int i = 0; i < Protocol.getProtocols().size(); i++){ |
|
313 |
protocols[i] = Protocol.getProtocols().get(i); |
|
314 |
protocolNames[i] = Protocol.getProtocols().get(i).getName() + " (" + Protocol.getProtocols().get(i).getDefaultPort() + ")"; |
|
315 |
if(Protocol.getProtocols().get(i).getName().equals("HTTP")){ |
|
316 |
httpIndex = i; |
|
317 |
} |
|
318 |
} |
|
319 |
protocolNames[protocolNames.length - 1] = "Custom"; |
|
320 |
|
|
321 |
ArrayAdapter<String> protocolAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, protocolNames); |
|
322 |
protocolAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
323 |
protocolSpinner.setAdapter(protocolAdapter); |
|
324 |
protocolSpinner.setSelection(httpIndex); |
|
325 |
|
|
326 |
} |
|
327 |
|
|
328 |
/* |
|
329 |
* this is the spinner for protocol selection that |
|
330 |
* appears if custom is chosen from protocolSpinner |
|
331 |
*/ |
|
332 |
private void loadProtocolSubSpinner() { |
|
333 |
protocolSubSpinner = (Spinner) findViewById(R.id.edit_protocol_sub_spinner); |
|
334 |
protocolSubSpinner.setOnItemSelectedListener(this); |
|
335 |
String protocolNames[] = new String[Protocol.getProtocols().size()]; |
|
336 |
|
|
337 |
for(int i = 0; i < Protocol.getProtocols().size(); i++){ |
|
338 |
protocolNames[i] = Protocol.getProtocols().get(i).getName(); |
|
339 |
} |
|
340 |
|
|
341 |
ArrayAdapter<String> protocolAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, protocolNames); |
|
342 |
protocolAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
343 |
protocolSubSpinner.setAdapter(protocolAdapter); |
|
344 |
} |
|
345 |
|
|
346 |
private void loadAlgorithmSpinner() { |
|
347 |
algorithmSpinner = (Spinner) findViewById(R.id.edit_algorithm_spinner); |
|
348 |
algorithmSpinner.setOnItemSelectedListener(this); |
|
349 |
String algorithmNames[] = new String[Algorithm.getAlgorithms().size()]; |
|
350 |
algorithms = new Algorithm[Algorithm.getAlgorithms().size()]; |
|
351 |
|
|
352 |
for(int i = 0; i < Algorithm.getAlgorithms().size(); i++){ |
|
353 |
algorithms[i] = Algorithm.getAlgorithms().get(i); |
|
354 |
algorithmNames[i] = getPrettyAlgoName(Algorithm.getAlgorithms().get(i).getName()); |
|
355 |
} |
|
356 |
|
|
357 |
ArrayAdapter<String> algorithmAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, algorithmNames); |
|
358 |
algorithmAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
|
359 |
algorithmSpinner.setAdapter(algorithmAdapter); |
|
360 |
} |
|
361 |
|
|
362 |
private String getPrettyAlgoName(String name){ |
|
363 |
if(name == null || name.length() == 0){ |
|
364 |
return ""; |
|
365 |
} else { |
|
366 |
String result = name.charAt(0) + ""; |
|
367 |
boolean previousWasSpace = false;; |
|
368 |
for(int i = 1; i < name.length(); i++){ |
|
369 |
char curLetter = name.charAt(i); |
|
370 |
if(curLetter == '_'){ |
|
371 |
result += " "; |
|
372 |
previousWasSpace = true; |
|
373 |
} else { |
|
374 |
if(previousWasSpace){ |
|
375 |
result += Character.toUpperCase(curLetter); |
|
376 |
} else { |
|
377 |
result += Character.toLowerCase(curLetter); |
|
378 |
} |
|
379 |
previousWasSpace = false; |
|
380 |
} |
|
381 |
} |
|
382 |
return result; |
|
383 |
} |
|
384 |
} |
|
385 |
|
|
386 |
private class AddLoadBalancerTask extends AsyncTask<Void, Void, HttpBundle> { |
|
387 |
private CloudServersException exception; |
|
388 |
|
|
389 |
protected void onPreExecute(){ |
|
390 |
showDialog(); |
|
391 |
} |
|
392 |
|
|
393 |
@Override |
|
394 |
protected HttpBundle doInBackground(Void... arg0) { |
|
395 |
HttpBundle bundle = null; |
|
396 |
try { |
|
397 |
bundle = (new LoadBalancerManager(getContext())).create(loadBalancer, LoadBalancer.getRegionUrl(selectedRegion)); |
|
398 |
} catch (CloudServersException e) { |
|
399 |
exception = e; |
|
400 |
} |
|
401 |
return bundle; |
|
402 |
} |
|
403 |
|
|
404 |
@Override |
|
405 |
protected void onPostExecute(HttpBundle bundle) { |
|
406 |
hideDialog(); |
|
407 |
HttpResponse response = bundle.getResponse(); |
|
408 |
if (response != null) { |
|
409 |
int statusCode = response.getStatusLine().getStatusCode(); |
|
410 |
if (statusCode == 202) { |
|
411 |
setResult(Activity.RESULT_OK); |
|
412 |
finish(); |
|
413 |
} else { |
|
414 |
CloudServersException cse = parseCloudServersException(response); |
|
415 |
if ("".equals(cse.getMessage())) { |
|
416 |
showError("There was a problem creating your load balancer.", bundle); |
|
417 |
} else { |
|
418 |
//if container with same name already exists |
|
419 |
showError("There was a problem creating your load balancer: " + cse.getMessage() + "\n See details for more information", bundle); |
|
420 |
} |
|
421 |
} |
|
422 |
} else if (exception != null) { |
|
423 |
showError("There was a problem creating your container: " + exception.getMessage()+"\n See details for more information.", bundle); |
|
424 |
} |
|
425 |
finish(); |
|
426 |
} |
|
427 |
} |
|
428 |
|
|
429 |
private void printNodes(ArrayList<Node> nodes){ |
|
430 |
for(Node n : nodes){ |
|
431 |
Log.d("info", "node is: " + n.getAddress()); |
|
432 |
} |
|
433 |
} |
|
434 |
|
|
435 |
@SuppressWarnings("unchecked") |
|
436 |
@Override |
|
437 |
protected void onActivityResult (int requestCode, int resultCode, Intent data){ |
|
438 |
if(requestCode == ADD_NODES_ACTIVITY_CODE && resultCode == RESULT_OK){ |
|
439 |
//set node list |
|
440 |
nodes = ((ArrayList<Node>)data.getSerializableExtra("nodes")); |
|
441 |
updateNodesIndicatorLight(); |
|
442 |
printNodes(nodes); |
|
443 |
} |
|
444 |
else if(requestCode == ADD_NODES_ACTIVITY_CODE && resultCode == RESULT_CANCELED){ |
|
445 |
//don't change list |
|
446 |
} |
|
447 |
else if(requestCode == SHARED_VIP_ACTIVITY_CODE){ |
|
448 |
if(data != null){ |
|
449 |
selectedVip = (VirtualIp)data.getSerializableExtra("selectedVip"); |
|
450 |
} |
|
451 |
updateVipIndicatorLight(); |
|
452 |
} |
|
453 |
} |
|
454 |
} |
Also available in: Unified diff