/* * RHQ Management Platform * Copyright (C) 2005-2014 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.coregui.client.bundle.deployment; import static org.rhq.coregui.client.CoreGUI.getErrorHandler; import static org.rhq.coregui.client.CoreGUI.getMessageCenter; import static org.rhq.coregui.client.CoreGUI.goToView; import static org.rhq.coregui.client.CoreGUI.isTagsEnabledForUI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import com.google.gwt.core.client.Duration; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.types.AnimationEffect; import com.smartgwt.client.types.AutoFitWidthApproach; import com.smartgwt.client.types.ListGridFieldType; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.IButton; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.CanvasItem; import com.smartgwt.client.widgets.form.fields.StaticTextItem; import com.smartgwt.client.widgets.form.fields.events.ClickEvent; import com.smartgwt.client.widgets.form.fields.events.ClickHandler; import com.smartgwt.client.widgets.grid.CellFormatter; import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import com.smartgwt.client.widgets.grid.events.SelectionChangedHandler; import com.smartgwt.client.widgets.grid.events.SelectionEvent; import com.smartgwt.client.widgets.layout.VLayout; import org.rhq.core.domain.bundle.Bundle; import org.rhq.core.domain.bundle.BundleDeployment; import org.rhq.core.domain.bundle.BundleDeploymentStatus; import org.rhq.core.domain.bundle.BundleResourceDeployment; import org.rhq.core.domain.bundle.BundleVersion; import org.rhq.core.domain.criteria.BundleCriteria; import org.rhq.core.domain.criteria.BundleDeploymentCriteria; import org.rhq.core.domain.criteria.BundleResourceDeploymentCriteria; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.tagging.Tag; import org.rhq.core.domain.util.PageList; import org.rhq.coregui.client.BookmarkableView; import org.rhq.coregui.client.ErrorMessageWindow; import org.rhq.coregui.client.ImageManager; import org.rhq.coregui.client.LinkManager; import org.rhq.coregui.client.ViewPath; import org.rhq.coregui.client.bundle.revert.BundleRevertWizard; import org.rhq.coregui.client.components.HeaderLabel; import org.rhq.coregui.client.components.TitleBar; import org.rhq.coregui.client.components.buttons.BackButton; import org.rhq.coregui.client.components.table.Table; import org.rhq.coregui.client.components.table.TimestampCellFormatter; import org.rhq.coregui.client.components.tagging.TagEditorView; import org.rhq.coregui.client.components.tagging.TagsChangedCallback; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.util.StringUtility; import org.rhq.coregui.client.util.enhanced.EnhancedIButton; import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor; import org.rhq.coregui.client.util.enhanced.EnhancedVLayout; import org.rhq.coregui.client.util.message.Message; /** * @author Greg Hinkle */ public class BundleDeploymentView extends EnhancedVLayout implements BookmarkableView { private BundleDeployment deployment; private BundleVersion version; private Bundle bundle; private VLayout detail; private boolean canDelete; private boolean canDeploy; private boolean canTag; private final HashMap<String, String> statusIcons; public BundleDeploymentView(boolean canDelete, boolean canDeploy, boolean canTag) { super(); this.canDelete = canDelete; this.canDeploy = canDeploy; this.canTag = canTag; setWidth100(); setHeight100(); //setMargin(10); // do not set margin, we already have our margin set outside of us statusIcons = new HashMap<String, String>(); statusIcons.put(BundleDeploymentStatus.PENDING.name(), "subsystems/bundle/install-loader.gif"); statusIcons.put(BundleDeploymentStatus.IN_PROGRESS.name(), "subsystems/bundle/install-loader.gif"); statusIcons.put(BundleDeploymentStatus.FAILURE.name(), "subsystems/bundle/Error_11.png"); statusIcons.put(BundleDeploymentStatus.MIXED.name(), "subsystems/bundle/Warning_11.png"); statusIcons.put(BundleDeploymentStatus.SUCCESS.name(), "subsystems/bundle/Ok_11.png"); } private void viewBundleDeployment(BundleDeployment bundleDeployment) { // Whenever a new view request comes in, make sure to clean house to avoid ID conflicts for sub-widgets this.destroyMembers(); this.deployment = bundleDeployment; this.version = bundleDeployment.getBundleVersion(); this.bundle = bundleDeployment.getBundleVersion().getBundle(); addMember(new BackButton(MSG.view_bundle_deploy_backButton() + ": " + deployment.getDestination().getName(), LinkManager.getBundleDestinationLink(version.getBundle().getId(), deployment.getDestination().getId()))); addMember(new HeaderLabel(Canvas.getImgURL("subsystems/bundle/BundleDeployment_24.png"), deployment.getName())); //conditionally add tags. Defaults to true, not available in JON builds. if (isTagsEnabledForUI()) { addMember(createTagEditor()); } addMember(createSummaryForm()); addMemberDeploymentsTable(); detail = new VLayout(); detail.setAutoHeight(); detail.hide(); addMember(detail); } private DynamicForm createSummaryForm() { DynamicForm form = new DynamicForm(); form.setWidth100(); form.setAutoHeight(); form.setNumCols(5); form.setWrapItemTitles(false); form.setExtraSpace(10); form.setIsGroup(true); form.setGroupTitle(MSG.common_title_summary()); form.setPadding(5); StaticTextItem bundleName = new StaticTextItem("bundle"); bundleName.setTitle(MSG.common_title_bundle()); bundleName.setValue("<a href=\"" + LinkManager.getBundleLink(bundle.getId()) + "\">" + StringUtility.escapeHtml(bundle.getName()) + "</a>"); CanvasItem actionItem = new CanvasItem("actions"); actionItem.setColSpan(1); actionItem.setRowSpan(4); actionItem.setShowTitle(false); actionItem.setCanvas(getActionLayout()); StaticTextItem bundleVersionName = new StaticTextItem("bundleVersion"); bundleVersionName.setTitle(MSG.view_bundle_bundleVersion()); bundleVersionName.setValue("<a href=\"" + LinkManager.getBundleVersionLink(bundle.getId(), deployment.getBundleVersion().getId()) + "\">" + StringUtility.escapeHtml(deployment.getBundleVersion().getVersion()) + "</a>"); StaticTextItem deployed = new StaticTextItem("deployed", MSG.view_bundle_deployed()); deployed.setValue(TimestampCellFormatter.format(deployment.getCtime(), TimestampCellFormatter.DATE_TIME_FORMAT_FULL)); StaticTextItem deployedBy = new StaticTextItem("deployedBy", MSG.view_bundle_deploy_deployedBy()); deployedBy.setValue(deployment.getSubjectName()); StaticTextItem destinationGroup = new StaticTextItem("group"); destinationGroup.setTitle(MSG.common_title_resource_group()); destinationGroup.setValue("<a href=\"" + LinkManager.getResourceGroupLink(deployment.getDestination().getGroup()) + "\">" + StringUtility.escapeHtml(deployment.getDestination().getGroup().getName()) + "</a>"); StaticTextItem destBaseDir = new StaticTextItem("destBaseDir", MSG.view_bundle_dest_baseDirName()); destBaseDir.setValue(deployment.getDestination().getDestinationSpecificationName()); StaticTextItem path = new StaticTextItem("path", MSG.view_bundle_deployDir()); path.setValue(deployment.getDestination().getDeployDir()); StaticTextItem description = new StaticTextItem("description", MSG.common_title_description()); description.setValue(StringUtility.escapeHtml(deployment.getDescription())); StaticTextItem status = new StaticTextItem("status", MSG.common_title_status()); status.setValue(deployment.getStatus().name()); status.setValueIcons(statusIcons); status.setValueIconHeight(11); status.setValueIconWidth(11); status.setShowValueIconOnly(true); if (deployment.getErrorMessage() != null) { status.setTooltip(MSG.view_bundle_deploy_clickForError()); status.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { ErrorMessageWindow win = new ErrorMessageWindow(MSG.common_severity_error(), "<pre>" + deployment.getErrorMessage() + "</pre>"); win.show(); } }); } form.setFields(bundleName, bundleVersionName, actionItem, deployed, deployedBy, destinationGroup, destBaseDir, description, path, status); return form; } private Canvas getActionLayout() { EnhancedVLayout actionLayout = new EnhancedVLayout(10); // we can only revert the live deployments, only show revert button when appropriate // in addition, we provide a purge button if you are viewing the live deployment, so // they can be shown an option to purge the platform content (since only the "live" // deployment represents content on the remote machines, showing purge only for live // deployments makes sense). if (deployment.isLive()) { IButton revertButton = new EnhancedIButton(MSG.view_bundle_revert(), ButtonColor.RED); //revertButton.setIcon("subsystems/bundle/BundleAction_Revert_16.png"); revertButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() { @Override public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) { new BundleRevertWizard(deployment.getDestination()).startWizard(); } }); actionLayout.addMember(revertButton); IButton purgeButton = new EnhancedIButton(MSG.view_bundle_purge(), ButtonColor.RED); //purgeButton.setIcon("subsystems/bundle/BundleDestinationAction_Purge_16.png"); purgeButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() { @Override public void onClick(com.smartgwt.client.widgets.events.ClickEvent clickEvent) { SC.ask(MSG.view_bundle_dest_purgeConfirm(), new BooleanCallback() { @Override public void execute(Boolean aBoolean) { if (aBoolean) { final int destinationId = deployment.getDestination().getId(); final String destinationName = deployment.getDestination().getName(); // 10m should be enough right? GWTServiceLookup.getBundleService(600000).purgeBundleDestination(destinationId, new AsyncCallback<Void>() { @Override public void onFailure(Throwable caught) { getErrorHandler().handleError( MSG.view_bundle_dest_purgeFailure(destinationName), caught); } @Override public void onSuccess(Void result) { getMessageCenter().notify( new Message(MSG.view_bundle_dest_purgeSuccessful(destinationName), Message.Severity.Info)); // Bundle destination is purged, go back to bundle deployment view - it is not live anymore goToView( LinkManager.getBundleDeploymentLink(bundle.getId(), deployment.getId()), true); } }); } } }); } }); actionLayout.addMember(purgeButton); if (!canDeploy) { revertButton.setDisabled(true); purgeButton.setDisabled(true); } } IButton deleteButton = new EnhancedIButton(MSG.common_button_delete(), ButtonColor.RED); //deleteButton.setIcon("subsystems/bundle/BundleDeploymentAction_Delete_16.png"); deleteButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() { @Override public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) { SC.ask(MSG.view_bundle_deploy_deleteConfirm(), new BooleanCallback() { @Override public void execute(Boolean confirmed) { if (confirmed) { doDeleteBundleDeployment(); } } }); } }); actionLayout.addMember(deleteButton); if (!canDelete) { deleteButton.setDisabled(true); } return actionLayout; } private void doDeleteBundleDeployment() { String deleteSubmittedMessage = MSG.view_bundle_deploy_deleteSubmitted(deployment.getName()); getMessageCenter().notify(new Message(deleteSubmittedMessage, Message.Severity.Info)); final Duration duration = new Duration(); GWTServiceLookup.getBundleService().deleteBundleDeployment(deployment.getId(), new AsyncCallback<Void>() { @Override public void onFailure(final Throwable caught) { Timer timer = new Timer() { @Override public void run() { String message = MSG.view_bundle_deploy_deleteFailure(deployment.getName()); getErrorHandler().handleError(message, caught); } }; // Delay the showing of the result to give the user some time to see the deleteSubmitted notif timer.schedule(Math.max(0, 3 * 1000 - duration.elapsedMillis())); } @Override public void onSuccess(Void result) { Timer timer = new Timer() { @Override public void run() { String message = MSG.view_bundle_deploy_deleteSuccessful(deployment.getName()); getMessageCenter().notify(new Message(message, Message.Severity.Info)); // Bundle deployment is deleted, go back to main bundle destinations view goToView( LinkManager.getBundleDestinationLink(bundle.getId(), deployment.getDestination().getId()), true); } }; // Delay the showing of the result to give the user some time to see the deleteSubmitted notif timer.schedule(Math.max(0, 3 * 1000 - duration.elapsedMillis())); } }); } private TagEditorView createTagEditor() { boolean readOnly = !this.canTag; TagEditorView tagEditor = new TagEditorView(version.getTags(), readOnly, new TagsChangedCallback() { @Override public void tagsChanged(HashSet<Tag> tags) { GWTServiceLookup.getTagService().updateBundleDeploymentTags(deployment.getId(), tags, new AsyncCallback<Void>() { @Override public void onFailure(Throwable caught) { getErrorHandler().handleError(MSG.view_bundle_deploy_tagUpdateFailure(), caught); } @Override public void onSuccess(Void result) { getMessageCenter().notify( new Message(MSG.view_bundle_deploy_tagUpdateSuccessful(), Message.Severity.Info)); } }); } }); tagEditor.setAutoHeight(); tagEditor.setExtraSpace(10); return tagEditor; } private Table addMemberDeploymentsTable() { Table table = new Table(MSG.view_bundle_deploy_deploymentPlatforms()); table.setShowFooterRefresh(false); TitleBar titleBar = new TitleBar(MSG.view_bundle_deploy_selectARow()); table.setTitleBar(titleBar); // resource icon field ResourceCategory resourceCategory = ResourceCategory.PLATFORM; try { resourceCategory = deployment.getDestination().getGroup().getResourceType().getCategory(); } catch (Exception skip) { // BZ 1027732 in case a group somehow got empty or switched to a mixed group, avoid NPE } ListGridField resourceIcon = new ListGridField("resourceAvailability"); HashMap<String, String> icons = new HashMap<String, String>(); icons.put(AvailabilityType.UP.name(), ImageManager.getResourceIcon(resourceCategory, AvailabilityType.UP)); icons.put(AvailabilityType.DOWN.name(), ImageManager.getResourceIcon(resourceCategory, AvailabilityType.DOWN)); icons.put(AvailabilityType.DISABLED.name(), ImageManager.getResourceIcon(resourceCategory, AvailabilityType.DISABLED)); icons.put(AvailabilityType.UNKNOWN.name(), ImageManager.getResourceIcon(resourceCategory, AvailabilityType.UNKNOWN)); resourceIcon.setValueIcons(icons); resourceIcon.setValueIconSize(16); resourceIcon.setType(ListGridFieldType.ICON); resourceIcon.setWidth(40); // resource field ListGridField resource = new ListGridField("resource", MSG.common_title_resource()); resource.setWidth("*"); resource.setCellFormatter(new CellFormatter() { @Override public String format(Object value, ListGridRecord listGridRecord, int i, int i1) { return "<a href=\"" + LinkManager.getResourceLink(listGridRecord.getAttributeAsInt("resourceId")) + "\">" + StringUtility.escapeHtml(String.valueOf(value)) + "</a>"; } }); // resource version field ListGridField resourceVersion = new ListGridField("resourceVersion", MSG.common_title_version()); resourceVersion.setAutoFitWidth(true); resourceVersion.setAutoFitWidthApproach(AutoFitWidthApproach.BOTH); // status icon field ListGridField status = new ListGridField("status", MSG.common_title_status()); status.setValueIcons(statusIcons); status.setValueIconHeight(11); status.setValueIconWidth(11); status.setShowValueIconOnly(true); status.setWidth(60); List<ListGridRecord> records = new ArrayList<ListGridRecord>(); for (BundleResourceDeployment rd : deployment.getResourceDeployments()) { ListGridRecord record = new ListGridRecord(); Resource rr = rd.getResource(); record.setAttribute("resource", rr.getName()); record.setAttribute("resourceAvailability", rr.getCurrentAvailability().getAvailabilityType().name()); record.setAttribute("resourceId", rr.getId()); record.setAttribute("resourceVersion", rr.getVersion()); record.setAttribute("status", rd.getStatus().name()); record.setAttribute("id", rd.getId()); record.setAttribute("object", rd); records.add(record); } // To get the ListGrid the Table must be initialized (via onInit()) by adding to the Canvas table.setHeight("30%"); table.setWidth100(); table.setShowResizeBar(true); table.setResizeBarTarget("next"); addMember(table); ListGrid listGrid = table.getListGrid(); listGrid.setFields(resourceIcon, resource, resourceVersion, status); listGrid.setData(records.toArray(new ListGridRecord[records.size()])); listGrid.addSelectionChangedHandler(new SelectionChangedHandler() { @Override public void onSelectionChanged(SelectionEvent selectionEvent) { if (selectionEvent.getState()) { BundleResourceDeployment bundleResourceDeployment = (BundleResourceDeployment) selectionEvent .getRecord().getAttributeAsObject("object"); BundleResourceDeploymentHistoryListView detailView = new BundleResourceDeploymentHistoryListView( bundleResourceDeployment); detail.removeMembers(detail.getMembers()); detail.addMember(detailView); detail.setHeight("50%"); detail.animateShow(AnimationEffect.SLIDE); } else { detail.animateHide(AnimationEffect.SLIDE); } } }); return table; } @Override public void renderView(final ViewPath viewPath) { int bundleDeploymentId = Integer.parseInt(viewPath.getCurrent().getPath()); BundleDeploymentCriteria criteria = new BundleDeploymentCriteria(); criteria.addFilterId(bundleDeploymentId); criteria.fetchBundleVersion(true); criteria.fetchConfiguration(true); criteria.fetchResourceDeployments(true); criteria.fetchDestination(true); criteria.fetchTags(true); GWTServiceLookup.getBundleService().findBundleDeploymentsByCriteria(criteria, new AsyncCallback<PageList<BundleDeployment>>() { @Override public void onFailure(Throwable caught) { getErrorHandler().handleError(MSG.view_bundle_deploy_loadFailure(), caught); } @Override public void onSuccess(PageList<BundleDeployment> result) { final BundleDeployment deployment = result.get(0); BundleCriteria bundleCriteria = new BundleCriteria(); bundleCriteria.addFilterId(deployment.getBundleVersion().getBundle().getId()); GWTServiceLookup.getBundleService().findBundlesByCriteria(bundleCriteria, new AsyncCallback<PageList<Bundle>>() { @Override public void onFailure(Throwable caught) { getErrorHandler().handleError(MSG.view_bundle_deploy_loadBundleFailure(), caught); } @Override public void onSuccess(PageList<Bundle> result) { final Bundle bundle = result.get(0); deployment.getBundleVersion().setBundle(bundle); BundleResourceDeploymentCriteria criteria = new BundleResourceDeploymentCriteria(); criteria.addFilterBundleDeploymentId(deployment.getId()); criteria.fetchResource(true); criteria.fetchBundleDeployment(true); GWTServiceLookup.getBundleService().findBundleResourceDeploymentsByCriteria(criteria, new AsyncCallback<PageList<BundleResourceDeployment>>() { @Override public void onFailure(Throwable caught) { getErrorHandler().handleError(MSG.view_bundle_deploy_loadFailure(), caught); } @Override public void onSuccess(PageList<BundleResourceDeployment> result) { deployment.setResourceDeployments(result); viewBundleDeployment(deployment); } }); } }); } }); } }