1package autotest.moblab.wizard; 2 3import com.google.gwt.event.dom.client.ClickEvent; 4import com.google.gwt.event.dom.client.ClickHandler; 5import com.google.gwt.event.logical.shared.ValueChangeEvent; 6import com.google.gwt.event.logical.shared.ValueChangeHandler; 7import com.google.gwt.json.client.JSONObject; 8import com.google.gwt.user.client.ui.Anchor; 9import com.google.gwt.user.client.ui.CheckBox; 10import com.google.gwt.user.client.ui.FlowPanel; 11import com.google.gwt.user.client.ui.InlineLabel; 12import com.google.gwt.user.client.ui.Label; 13import com.google.gwt.user.client.ui.PopupPanel; 14import com.google.gwt.user.client.ui.TextBox; 15 16import autotest.common.Utils; 17import autotest.moblab.rpc.CloudStorageInfo; 18import autotest.moblab.rpc.MoblabRpcCallbacks; 19import autotest.moblab.rpc.MoblabRpcHelper; 20import autotest.moblab.rpc.OperationStatus; 21import autotest.common.ui.ToolTip; 22 23import java.util.HashMap; 24 25/** 26 * Wizard card for cloud storage configuration. 27 */ 28public class CloudStorageCard extends FlexWizardCard { 29 /** 30 * The cached cloud storage information. 31 */ 32 private CloudStorageInfo cloudStorageInfo; 33 34 /** 35 * Checkbox for if reuse existing boto file. 36 */ 37 private CheckBox chkUseExisting; 38 39 public CloudStorageCard() { 40 super(); 41 setViewTitle("Google Cloud Storage Configuration"); 42 setEditTitle("Configure Access to Google Cloud Storage"); 43 } 44 45 @Override 46 protected void updateModeUI() { 47 if (cloudStorageInfo != null) { 48 resetUI(); 49 int row = 0; 50 // In edit mode, display the check box for re-using existing boto file. 51 if (ConfigWizard.Mode.Edit == getMode()) { 52 chkUseExisting = new CheckBox("Use Existing Boto File on Moblab Device."); 53 layoutTable.setWidget(row, 1, chkUseExisting); 54 chkUseExisting.addValueChangeHandler(new ValueChangeHandler<Boolean>() { 55 @Override 56 public void onValueChange(ValueChangeEvent<Boolean> event) { 57 if (cloudStorageInfo != null) { 58 cloudStorageInfo.setUseExistingBotoFile(event.getValue()); 59 } 60 TextBox box = getValueFieldEditor(CloudStorageInfo.JSON_FIELD_BOTO_KEY_ID); 61 if (box != null) { 62 box.setEnabled(!event.getValue()); 63 } 64 box = getValueFieldEditor(CloudStorageInfo.JSON_FIELD_BOTO_SECRET_KEY); 65 if (box != null) { 66 box.setEnabled(!event.getValue()); 67 } 68 } 69 }); 70 71 } 72 73 // Row for boto key id. 74 row++; 75 76 // show a tooltip describing what a boto key is 77 FlowPanel botoKeyPanel = new FlowPanel(); 78 botoKeyPanel.add(new InlineLabel("Boto Key ID ")); 79 Anchor botoKeyHelp = new Anchor("?"); 80 botoKeyHelp.addClickHandler(new ClickHandler() { 81 @Override 82 public void onClick(ClickEvent event) { 83 PopupPanel popup = new PopupPanel(true); 84 String helpText = "A boto key is used to access Google storage " + 85 "buckets. Please contact your Google PM for a boto key if you " + 86 "haven't received one already."; 87 popup.setWidget(new Label(helpText)); 88 popup.showRelativeTo(layoutTable); 89 } 90 }); 91 botoKeyPanel.add(botoKeyHelp); 92 93 layoutTable.setWidget(row, 0, botoKeyPanel); 94 layoutTable.setWidget(row, 1, createValueFieldWidget(CloudStorageInfo.JSON_FIELD_BOTO_KEY_ID, 95 cloudStorageInfo.getBotoKey())); 96 97 // Row for boto key secret. 98 row++; 99 layoutTable.setWidget(row, 0, new Label("Boto Key Secret")); 100 layoutTable.setWidget(row, 1, createStringValueFieldWidget( 101 CloudStorageInfo.JSON_FIELD_BOTO_SECRET_KEY, cloudStorageInfo.getBotoSecret(), true)); 102 103 // Row for image storage bucket url. 104 row++; 105 layoutTable.setWidget(row, 0, new Label("Image Storage Bucket URL")); 106 String url = cloudStorageInfo.getImageStorageServer(); 107 layoutTable.setWidget(row, 1, 108 createValueFieldWidget(CloudStorageInfo.JSON_FIELD_IMAGE_STORAGE_URL, url)); 109 if (url != null && ConfigWizard.Mode.View == getMode()) { 110 Anchor link = Utils.createGoogleStorageHttpUrlLink("link", url); 111 layoutTable.setWidget(row, 2, link); 112 } 113 114 if (ConfigWizard.Mode.Edit == getMode()) { 115 chkUseExisting.setValue(cloudStorageInfo.isUseExistingBotoFile(), true); 116 } 117 } else { 118 MoblabRpcHelper.fetchCloudStorageInfo(new MoblabRpcCallbacks.FetchCloudStorageInfoCallback() { 119 @Override 120 public void onCloudStorageInfoFetched(CloudStorageInfo info) { 121 cloudStorageInfo = info; 122 updateModeUI(); 123 } 124 }); 125 } 126 } 127 128 @Override 129 public void validate(final CardValidationCallback callback) { 130 // If not use existing boto, than boto id and boto secret fields can not be empty. 131 if (!chkUseExisting.getValue()) { 132 cloudStorageInfo 133 .setBotoKey(getStringValueFieldValue(CloudStorageInfo.JSON_FIELD_BOTO_KEY_ID)); 134 cloudStorageInfo 135 .setBotoSecret(getStringValueFieldValue(CloudStorageInfo.JSON_FIELD_BOTO_SECRET_KEY)); 136 } 137 cloudStorageInfo.setImageStorageServer( 138 getStringValueFieldValue(CloudStorageInfo.JSON_FIELD_IMAGE_STORAGE_URL)); 139 if (!chkUseExisting.getValue()) { 140 // Boto key and secret are required. 141 if (cloudStorageInfo.getBotoKey() == null || cloudStorageInfo.getBotoSecret() == null) { 142 callback.onValidationStatus( 143 new OperationStatus(false, "The boto key fields could not be empty")); 144 return; 145 } 146 // Image bucket and result bucket can not be empty. 147 if (cloudStorageInfo.getImageStorageServer() == null) { 148 callback.onValidationStatus( 149 new OperationStatus(false, "The image bucket URL fields could not be empty")); 150 return; 151 } 152 } 153 // Image bucket and result bucket must end in /. 154 if (cloudStorageInfo.getImageStorageServer().substring( 155 cloudStorageInfo.getImageStorageServer().length() - 1) != "/") { 156 callback.onValidationStatus( 157 new OperationStatus(false, "The image bucket URL must end in /")); 158 return; 159 } 160 161 // Sends validation request to server to validate the boto key and bucket urls. 162 MoblabRpcHelper.validateCloudStorageInfo(cloudStorageInfo, 163 new MoblabRpcCallbacks.ValidateCloudStorageInfoCallback() { 164 @Override 165 public void onCloudStorageInfoValidated(OperationStatus status) { 166 if (!status.isOk()) { 167 callback.onValidationStatus(status); 168 return; 169 } 170 CloudStorageCard.super.validate(callback); 171 } 172 }); 173 return; 174 } 175 176 /** 177 * Gets the string input field value. 178 */ 179 protected String getStringValueFieldValue(String fieldId) { 180 TextBox textBox = getValueFieldEditor(fieldId); 181 String value = textBox.getValue(); 182 if (value != null) { 183 value = value.trim(); 184 } 185 186 if (value == null || value.length() == 0) { 187 return null; 188 } 189 return value; 190 } 191 192 @Override 193 public void resetData() { 194 cloudStorageInfo = null; 195 super.resetData(); 196 } 197 198 @Override 199 public void collectConfigData(@SuppressWarnings("unused") HashMap<String, JSONObject> map) { 200 if (map != null && cloudStorageInfo != null) { 201 map.put(MoblabRpcHelper.RPC_PARAM_CLOUD_STORAGE_INFO, cloudStorageInfo.toJson()); 202 } 203 } 204} 205