/* * RHQ Management Platform * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.coregui.client.bundle.create; import java.util.LinkedHashMap; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.FormLayoutType; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.events.FormSubmitFailedEvent; import com.smartgwt.client.widgets.form.events.FormSubmitFailedHandler; import com.smartgwt.client.widgets.form.fields.ButtonItem; import com.smartgwt.client.widgets.form.fields.CanvasItem; import com.smartgwt.client.widgets.form.fields.PasswordItem; import com.smartgwt.client.widgets.form.fields.TextAreaItem; import com.smartgwt.client.widgets.form.fields.TextItem; import com.smartgwt.client.widgets.form.fields.events.ClickEvent; import com.smartgwt.client.widgets.form.fields.events.ClickHandler; import org.rhq.core.domain.bundle.BundleNotFoundException; import org.rhq.core.domain.bundle.BundleVersion; import org.rhq.core.domain.bundle.composite.BundleGroupAssignmentComposite; import org.rhq.core.domain.criteria.BundleVersionCriteria; import org.rhq.core.domain.util.PageList; import org.rhq.coregui.client.CoreGUI; import org.rhq.coregui.client.ImageManager; import org.rhq.coregui.client.components.form.RadioGroupWithComponentsItem; import org.rhq.coregui.client.components.upload.BundleDistributionFileUploadForm; import org.rhq.coregui.client.components.upload.DynamicCallbackForm; import org.rhq.coregui.client.components.upload.DynamicFormHandler; import org.rhq.coregui.client.components.upload.DynamicFormSubmitCompleteEvent; import org.rhq.coregui.client.components.upload.TextFileRetrieverForm; import org.rhq.coregui.client.components.wizard.AbstractWizardStep; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.util.StringUtility; import org.rhq.coregui.client.util.message.Message; import org.rhq.coregui.client.util.message.Message.Severity; public class BundleUploadDistroFileStep extends AbstractWizardStep { private final AbstractBundleCreateWizard wizard; private DynamicForm mainCanvasForm; private TextItem urlTextItem; private TextItem urlUserNameItem; private PasswordItem urlPasswordItem; private BundleDistributionFileUploadForm uploadDistroForm; private DynamicCallbackForm recipeForm; private RadioGroupWithComponentsItem radioGroup; private static final String URL_OPTION = MSG.view_bundle_createWizard_urlOption(); private static final String UPLOAD_OPTION = MSG.view_bundle_createWizard_uploadOption(); private static final String RECIPE_OPTION = MSG.view_bundle_createWizard_recipeOption(); private static final String URL_OPTION_USERNAME = MSG.common_title_username(); private static final String URL_OPTION_PASSWORD = MSG.common_title_password(); private static final String URL_OPTION_TOOLTIP = MSG.view_bundle_createWizard_urlTooltip(); final String BUNDLE_NOT_FOUND_EXCEPTION_PATTERN_START = "org.rhq.core.domain.bundle.BundleNotFoundException:["; final String BUNDLE_NOT_FOUND_EXCEPTION_PATTERN_END = "]"; public BundleUploadDistroFileStep(AbstractBundleCreateWizard bundleCreationWizard) { this.wizard = bundleCreationWizard; } @Override public Canvas getCanvas() { if (mainCanvasForm == null) { LinkedHashMap<String, DynamicForm> radioItems = new LinkedHashMap<String, DynamicForm>(); radioItems.put(URL_OPTION, createUrlForm()); radioItems.put(UPLOAD_OPTION, createUploadForm()); radioItems.put(RECIPE_OPTION, createRecipeForm()); mainCanvasForm = new RadioDynamicForm(); radioGroup = new RadioGroupWithComponentsItem("bundleDistRadioGroup", MSG.view_bundle_createWizard_bundleDistro(), radioItems, mainCanvasForm); radioGroup.setShowTitle(false); mainCanvasForm.setItems(radioGroup); } // If we've already created a bundle version, don't allow the user to submit something else. // The user must hit the cancel button and start over if they want to use a different bundle distribution file. if (wizard.getBundleVersion() != null) { mainCanvasForm.setDisabled(true); } return mainCanvasForm; } @Override public boolean nextPage() { wizard.getView().hideMessage(); if (uploadDistroForm.isUploadInProgress()) { handleUploadError(MSG.view_bundle_createWizard_uploadInProgress(), false); return false; } if (wizard.getBundleVersion() == null) { String selected = radioGroup.getSelected(); if (URL_OPTION.equals(selected)) { processUrl(); } else if (UPLOAD_OPTION.equals(selected)) { uploadDistroForm.submitForm(); // on certain errors the form may never be submitted, report these errors outside submit handlers handleUploadError(uploadDistroForm.getUploadError(), false); } else if (RECIPE_OPTION.equals(selected)) { processRecipe(); } else { wizard.getView().showMessage(MSG.view_bundle_createWizard_youMustChooseOne()); return false; } return false; } else { // there is already a bundle version, so we must have created it already // and the user must have reached here after hitting the previous button earlier; // just move to the next step to let the user peruse the wizard steps return true; } } @Override public String getName() { return MSG.view_bundle_createWizard_provideBundleDistro(); } private DynamicForm createUrlForm() { urlTextItem = new TextItem("url", URL_OPTION); urlTextItem.setTooltip(URL_OPTION_TOOLTIP); urlTextItem.setRequired(false); urlTextItem.setShowTitle(false); urlTextItem.setWidth(400); urlTextItem.setColSpan(4); urlUserNameItem = new TextItem("username", URL_OPTION_USERNAME); urlUserNameItem.setTooltip(URL_OPTION_TOOLTIP); urlUserNameItem.setRequired(false); urlUserNameItem.setShowTitle(true); urlUserNameItem.setWidth(100); urlUserNameItem.setColSpan(1); urlUserNameItem.setAlign(Alignment.LEFT); urlPasswordItem = new PasswordItem("password", URL_OPTION_PASSWORD); urlPasswordItem.setAttribute("autocomplete", "off"); urlPasswordItem.setTooltip(URL_OPTION_TOOLTIP); urlPasswordItem.setRequired(false); urlPasswordItem.setShowTitle(true); urlPasswordItem.setWidth(100); urlPasswordItem.setColSpan(1); urlUserNameItem.setAlign(Alignment.RIGHT); DynamicForm urlForm = new DynamicForm(); urlForm.setItemLayout(FormLayoutType.TABLE); urlForm.setNumCols(4); urlForm.setPadding(20); urlForm.setWidth100(); urlForm.setItems(urlTextItem, urlUserNameItem, urlPasswordItem); return urlForm; } private BundleDistributionFileUploadForm createUploadForm() { uploadDistroForm = new BundleDistributionFileUploadForm(false); uploadDistroForm.setPadding(20); uploadDistroForm.setWidth(400); uploadDistroForm.addFormHandler(new DynamicFormHandler() { @Override public void onSubmitComplete(DynamicFormSubmitCompleteEvent event) { processUpload(); } }); uploadDistroForm.addFormSubmitFailedHandler(new FormSubmitFailedHandler() { @Override public void onFormSubmitFailed(FormSubmitFailedEvent event) { return; // the distro form component will log an error for us } }); return uploadDistroForm; } private DynamicForm createRecipeForm() { recipeForm = new DynamicCallbackForm("recipeForm"); recipeForm.setMargin(Integer.valueOf(20)); recipeForm.setShowInlineErrors(false); final ButtonItem showUpload = new ButtonItem("recipeUploadLink", MSG.view_bundle_createWizard_clickToUploadRecipe()); showUpload.setIcon(ImageManager.getUploadIcon()); final CanvasItem upload = new CanvasItem("recipeUploadCanvas"); upload.setShowTitle(false); upload.setVisible(false); final TextFileRetrieverForm textFileRetrieverForm = new TextFileRetrieverForm(); upload.setCanvas(textFileRetrieverForm); showUpload.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent clickEvent) { showUpload.hide(); upload.show(); recipeForm.markForRedraw(); } }); final TextAreaItem recipe = new TextAreaItem("recipeText"); recipe.setShowTitle(false); recipe.setRequired(false); recipe.setColSpan(4); recipe.setWidth(400); recipe.setHeight(150); textFileRetrieverForm.addFormHandler(new DynamicFormHandler() { /* * Helper method to unescape a string which has been escaped for inclusion in HTML tags */ public String htmlUnescape(String escapedHtml) { Element e = Document.get().createDivElement(); e.setInnerHTML(escapedHtml); return e.getInnerText(); } @Override public void onSubmitComplete(DynamicFormSubmitCompleteEvent event) { wizard.setRecipe(htmlUnescape(event.getResults())); recipe.setValue(htmlUnescape(event.getResults())); textFileRetrieverForm.retrievalStatus(true); showUpload.show(); upload.hide(); recipeForm.markForRedraw(); } }); recipeForm.setItems(showUpload, upload, recipe); return recipeForm; } private void processUrl() { String urlString = (String) this.urlTextItem.getValue(); String urlUserName = (String) this.urlUserNameItem.getValue(); String urlPassword = (String) this.urlPasswordItem.getValue(); if (urlString == null || urlString.trim().length() == 0) { wizard.getView().showMessage(MSG.view_bundle_createWizard_enterUrl()); wizard.setBundleVersion(null); setButtonsDisableMode(false); return; } // if upload takes more than 10m, you have other things to worry about GWTServiceLookup.getBundleService(10 * 60 * 1000).createOrStoreBundleVersionViaURL(urlString, urlUserName, urlPassword, new AsyncCallback<BundleVersion>() { @Override public void onSuccess(BundleVersion result) { CoreGUI.getMessageCenter().notify( new Message( MSG.view_bundle_createWizard_createSuccessful(result.getName(), result.getVersion()), Message.Severity.Info)); wizard.setBundleVersion(result); setButtonsDisableMode(false); incrementStep(); // go to the next step } @Override public void onFailure(Throwable caught) { // This signals that the bundle does not yet exist BundleNotFoundException bnfe = unpackBundleNotFoundException(caught); if (bnfe != null) { handleBundleNotFoundException(bnfe); } else { // Escape it, since it contains the URL, which the user entered. String message = StringUtility.escapeHtml(caught.getMessage()); wizard.getView().showMessage(message); CoreGUI.getErrorHandler().handleError(MSG.view_bundle_createWizard_createFailure(), caught); wizard.setBundleVersion(null); setButtonsDisableMode(false); } } }); } private BundleNotFoundException unpackBundleNotFoundException(Throwable caught) { if (caught instanceof BundleNotFoundException) { String message = caught.getMessage(); if (message.startsWith("[") && message.endsWith("]")) { return new BundleNotFoundException(message.substring(1, message.length()-1)); } } return null; } private void handleBundleNotFoundException(BundleNotFoundException e) { String token = e.getMessage(); if (null == token || token.isEmpty()) { wizard.getView().showMessage("BundleNotFound: Unexpected failure creating bundle version."); CoreGUI.getErrorHandler().handleError(MSG.view_bundle_createWizard_createFailure(), e); wizard.setBundleVersion(null); setButtonsDisableMode(false); } wizard.setCreateInitialBundleVersionToken(token); setButtonsDisableMode(false); incrementStep(); // go to the next step } private void incrementStep() { // before moving to the next step, get the assignable/assigned bundle groups for this new bundle version boolean isInitialVersion = this.wizard.getBundleVersion() == null || this.wizard.getBundleVersion().getVersionOrder() == 0; int bundleId = isInitialVersion ? 0 : this.wizard.getBundleVersion().getBundle().getId(); GWTServiceLookup.getBundleService().getAssignableBundleGroups(bundleId, new AsyncCallback<BundleGroupAssignmentComposite>() { public void onSuccess(BundleGroupAssignmentComposite result) { wizard.setBundleGroupAssignmentComposite(result); wizard.getView().incrementStep(); // go to the next step } public void onFailure(Throwable caught) { setButtonsDisableMode(false); String message = MSG.view_bundle_createWizard_groupsStep_failedGetAssignable(); wizard.getView().showMessage(message); CoreGUI.getErrorHandler().handleError(message, caught); } }); } private void processUpload() { if (Boolean.TRUE.equals(uploadDistroForm.getUploadResult())) { if (null != uploadDistroForm.getCreateInitialBundleVersionToken()) { handleBundleNotFoundException(new BundleNotFoundException( uploadDistroForm.getCreateInitialBundleVersionToken())); } else { int bvId = uploadDistroForm.getBundleVersionId(); BundleVersionCriteria criteria = new BundleVersionCriteria(); criteria.addFilterId(bvId); criteria.fetchBundle(true); GWTServiceLookup.getBundleService().findBundleVersionsByCriteria(criteria, new AsyncCallback<PageList<BundleVersion>>() { @Override public void onSuccess(PageList<BundleVersion> result) { BundleVersion bv = result.get(0); CoreGUI.getMessageCenter().notify( new Message(MSG.view_bundle_createWizard_createSuccessful(bv.getName(), bv.getVersion()), Message.Severity.Info)); wizard.setBundleVersion(bv); setButtonsDisableMode(false); incrementStep(); // go to the next step } @Override public void onFailure(Throwable caught) { wizard.getView().showMessage(caught.getMessage()); CoreGUI.getErrorHandler().handleError(MSG.view_bundle_createWizard_createFailure(), caught); wizard.setBundleVersion(null); setButtonsDisableMode(false); } }); } } else { String errorMessage = uploadDistroForm.getUploadError(); handleUploadError(errorMessage, true); wizard.setBundleVersion(null); setButtonsDisableMode(false); } } private void processRecipe() { String recipeString = (String) this.recipeForm.getItem("recipeText").getValue(); if (recipeString == null || recipeString.trim().length() == 0) { wizard.getView().showMessage(MSG.view_bundle_createWizard_enterRecipe()); wizard.setBundleVersion(null); setButtonsDisableMode(false); return; } this.wizard.setRecipe(recipeString); GWTServiceLookup.getBundleService().createBundleVersionViaRecipe(this.wizard.getRecipe(), new AsyncCallback<BundleVersion>() { @Override public void onSuccess(BundleVersion result) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_bundle_createWizard_createSuccessful(result.getName(), result.getVersion()), Message.Severity.Info)); wizard.setBundleVersion(result); setButtonsDisableMode(false); incrementStep(); // go to the next step } @Override public void onFailure(Throwable caught) { boolean handled = false; String message = caught.getMessage(); if (message.contains("PermissionException") && message.contains("initial")) { handled = true; wizard.setCreateInitialBundleVersionRecipe(wizard.getRecipe()); setButtonsDisableMode(false); incrementStep(); // go to the next step } if (!handled) { wizard.getView().showMessage(caught.getMessage()); CoreGUI.getErrorHandler().handleError(MSG.view_bundle_createWizard_createFailure(), caught); wizard.setBundleVersion(null); wizard.setRecipe(""); setButtonsDisableMode(false); } } }); } private void setButtonsDisableMode(boolean disabled) { wizard.getView().getCancelButton().setDisabled(disabled); wizard.getView().getNextButton().setDisabled(disabled); } private void handleUploadError(String errorMessage, boolean sendToMessageCenter) { if (null != errorMessage) { wizard.getView().showMessage(errorMessage); } else { errorMessage = ""; } if (sendToMessageCenter) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_bundle_createWizard_failedToUploadDistroFile(), errorMessage, Severity.Error)); } } private class RadioDynamicForm extends DynamicForm { public RadioDynamicForm() { super(); } @Override public void destroy() { radioGroup.destroyComponents(); super.destroy(); } } }