/*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.coregui.client.bundle.list;
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.HashSet;
import java.util.Set;
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.data.Criteria;
import com.smartgwt.client.types.Overflow;
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.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
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.layout.VLayout;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.bundle.Bundle;
import org.rhq.core.domain.criteria.BundleCriteria;
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.IconEnum;
import org.rhq.coregui.client.PermissionsLoadedListener;
import org.rhq.coregui.client.PermissionsLoader;
import org.rhq.coregui.client.ViewId;
import org.rhq.coregui.client.ViewPath;
import org.rhq.coregui.client.bundle.BundleTopView;
import org.rhq.coregui.client.bundle.deploy.BundleDeployWizard;
import org.rhq.coregui.client.bundle.deployment.BundleDeploymentView;
import org.rhq.coregui.client.bundle.destination.BundleDestinationListView;
import org.rhq.coregui.client.bundle.destination.BundleDestinationView;
import org.rhq.coregui.client.bundle.group.BundleGroupsListView;
import org.rhq.coregui.client.bundle.version.BundleVersionListView;
import org.rhq.coregui.client.bundle.version.BundleVersionView;
import org.rhq.coregui.client.components.HeaderLabel;
import org.rhq.coregui.client.components.buttons.BackButton;
import org.rhq.coregui.client.components.table.Table;
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;
public class BundleView extends EnhancedVLayout implements BookmarkableView {
private int bundleBeingViewed = 0;
private TabSet tabs;
private Tab versionsTab;
private Tab destinationsTab;
private Set<Permission> globalPermissions;
private int permissionCheckBundleId = 0;
private boolean canDelete;
private boolean canDeploy;
private boolean canTag;
private Bundle bundle;
public BundleView(Set<Permission> perms) {
super();
this.globalPermissions = perms;
setWidth100();
setHeight100();
setMargin(10);
setOverflow(Overflow.AUTO);
}
private void viewBundle(final Bundle bundle, final ViewId nextViewId) {
// Whenever a new view request comes in, make sure to clean house to avoid ID conflicts for sub-widgets
this.destroyMembers();
this.bundle = bundle;
BackButton backButton = new BackButton(MSG.view_bundle_list_backToAll(), BundleTopView.VIEW_ID.getName());
HeaderLabel headerLabel = new HeaderLabel(IconEnum.BUNDLE.getIcon24x24Path(), StringUtility.escapeHtml(bundle
.getName()));
tabs = new TabSet();
versionsTab = createVersionsTab();
destinationsTab = createDestinationsTab();
Tab bundleGroupsTab = createBundleGroupsTab();
tabs.addTab(versionsTab);
tabs.addTab(destinationsTab);
tabs.addTab(bundleGroupsTab);
addMember(backButton);
addMember(headerLabel);
//conditionally add tags. Defaults to true, not available in JON builds.
if (isTagsEnabledForUI()) {
addMember(createTagEditor());
}
addMember(createSummaryForm());
addMember(tabs);
// select the correct tab based on what URL the user is going to (based on what tree node was selected)
if ((null == nextViewId) || (nextViewId.getPath().equals("versions"))) {
tabs.selectTab(versionsTab);
} else if (nextViewId.getPath().equals("destinations")) {
tabs.selectTab(destinationsTab);
}
markForRedraw();
}
private TagEditorView createTagEditor() {
boolean readOnly = !canTag;
TagEditorView tagEditor = new TagEditorView(bundle.getTags(), readOnly, new TagsChangedCallback() {
@Override
public void tagsChanged(HashSet<Tag> tags) {
GWTServiceLookup.getTagService().updateBundleTags(bundleBeingViewed, tags, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
getErrorHandler().handleError(MSG.view_bundle_list_tagUpdateFailure(), caught);
}
@Override
public void onSuccess(Void result) {
String conciseMessage = MSG.view_bundle_list_tagUpdateSuccessful();
getMessageCenter().notify(new Message(conciseMessage, Message.Severity.Info));
}
});
}
});
tagEditor.setAutoHeight();
tagEditor.setExtraSpace(10);
return tagEditor;
}
private Tab createDestinationsTab() {
Tab destinationsTab = new Tab(MSG.view_bundle_destinations());
Criteria criteria = new Criteria();
criteria.addCriteria("bundleId", bundle.getId());
destinationsTab.setPane(new BundleDestinationListView(criteria));
return destinationsTab;
}
private Tab createVersionsTab() {
Tab versionsTab = new Tab(MSG.view_bundle_versions());
Criteria criteria = new Criteria();
criteria.addCriteria("bundleId", bundleBeingViewed);
Table bundleVersionsTable = new BundleVersionListView(criteria);
versionsTab.setPane(bundleVersionsTable);
return versionsTab;
}
private Tab createBundleGroupsTab() {
Tab bundleGroupsTab = new Tab(MSG.common_title_bundleGroups());
Criteria criteria = new Criteria();
criteria.addCriteria("bundleIds", new Integer[] { bundle.getId() });
bundleGroupsTab.setPane(new BundleGroupsListView(criteria, null));
return bundleGroupsTab;
}
private DynamicForm createSummaryForm() {
DynamicForm form = new DynamicForm();
form.setWidth100();
form.setColWidths("20%", "40%", "40%");
form.setNumCols(3);
form.setAutoHeight();
form.setWrapItemTitles(false);
form.setExtraSpace(10);
form.setIsGroup(true);
form.setGroupTitle(MSG.common_title_summary());
form.setPadding(5);
CanvasItem actionItem = new CanvasItem("actions");
actionItem.setColSpan(1);
actionItem.setRowSpan(3);
actionItem.setShowTitle(false);
actionItem.setCanvas(getActionCanvas());
StaticTextItem versionCountItem = new StaticTextItem("versionCount", MSG.view_bundle_list_versionsCount());
versionCountItem.setValue(bundle.getBundleVersions() != null ? bundle.getBundleVersions().size() : 0);
StaticTextItem destinationsCountItem = new StaticTextItem("destinationsCount",
MSG.view_bundle_list_destinationsCount());
destinationsCountItem.setValue(bundle.getDestinations() != null ? bundle.getDestinations().size() : 0);
StaticTextItem descriptionItem = new StaticTextItem("description", MSG.common_title_description());
descriptionItem.setValue(StringUtility.escapeHtml(bundle.getDescription()));
form.setFields(versionCountItem, actionItem, destinationsCountItem, descriptionItem);
return form;
}
private Canvas getActionCanvas() {
VLayout layout = new EnhancedVLayout(10);
IButton deployButton = new EnhancedIButton(MSG.view_bundle_deploy(), ButtonColor.BLUE);
//deployButton.setIcon(IconEnum.BUNDLE_DEPLOY.getIcon16x16Path());
deployButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
// can change this back to SINGLE selection when we feel like it. currently allowing the wizard to
// select the bundle.
BundleCriteria bc = new BundleCriteria();
bc.addFilterId(bundle.getId());
GWTServiceLookup.getBundleService().findBundlesByCriteria(bc, new AsyncCallback<PageList<Bundle>>() {
@Override
public void onFailure(Throwable caught) {
getErrorHandler().handleError(MSG.view_bundle_list_error1(bundle.getName()), caught);
}
@Override
public void onSuccess(PageList<Bundle> result) {
if (result == null || result.size() != 1) {
String conciseMessage = MSG.view_bundle_list_error2(bundle.getName());
getMessageCenter().notify(new Message(conciseMessage, Message.Severity.Error));
return;
}
new BundleDeployWizard(result.get(0)).startWizard();
}
});
}
});
layout.addMember(deployButton);
IButton deleteButton = new EnhancedIButton(MSG.common_button_delete(), ButtonColor.RED);
//deleteButton.setIcon(IconEnum.BUNDLE_DELETE.getIcon16x16Path());
deleteButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
SC.ask(MSG.view_bundle_deleteConfirm(), new BooleanCallback() {
@Override
public void execute(Boolean confirmed) {
if (confirmed) {
doDeleteBundle();
}
}
});
}
});
layout.addMember(deleteButton);
deployButton.setDisabled(!canDeploy);
deleteButton.setDisabled(!canDelete);
return layout;
}
private void doDeleteBundle() {
String deleteSubmittedMessage = MSG.view_bundle_deleteSubmitted(bundle.getName());
getMessageCenter().notify(new Message(deleteSubmittedMessage, Message.Severity.Info));
final Duration duration = new Duration();
GWTServiceLookup.getBundleService().deleteBundle(bundleBeingViewed, new AsyncCallback<Void>() {
@Override
public void onFailure(final Throwable caught) {
Timer timer = new Timer() {
@Override
public void run() {
String message = MSG.view_bundle_list_deleteFailure(bundle.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 conciseMessage = MSG.view_bundle_list_deleteSuccessful(bundle.getName());
getMessageCenter().notify(new Message(conciseMessage, Message.Severity.Info));
goToView("Bundles", true); // Bundle is deleted, go back to all bundles view
}
};
// 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 renderView(final ViewPath viewPath) {
final int bundleId = Integer.parseInt(viewPath.getCurrent().getPath());
// if we have already determined permissions for this bundle, just proceed
if (permissionCheckBundleId == bundleId) {
authorizedRenderView(bundleId, viewPath);
return;
}
// check necessary global permissions
canDelete = globalPermissions.contains(Permission.DELETE_BUNDLES);
canDeploy = globalPermissions.contains(Permission.DEPLOY_BUNDLES);
canTag = globalPermissions.contains(Permission.CREATE_BUNDLES);
// If the user has global perms to enable/render any of the views then proceed, otherwise, we
// need to see what bundle level perms he has.
if (canDelete && canDeploy && canTag) {
authorizedRenderView(bundleId, viewPath);
} else {
new PermissionsLoader().loadBundlePermissions(bundleId, new PermissionsLoadedListener() {
@Override
public void onPermissionsLoaded(Set<Permission> bundlePermissions) {
canDelete = canDelete || bundlePermissions.contains(Permission.DELETE_BUNDLES_FROM_GROUP);
canDeploy = canDeploy || bundlePermissions.contains(Permission.DEPLOY_BUNDLES_TO_GROUP);
canTag = canTag || bundlePermissions.contains(Permission.CREATE_BUNDLES_IN_GROUP);
authorizedRenderView(bundleId, viewPath);
}
});
}
}
private void authorizedRenderView(final int bundleId, final ViewPath viewPath) {
permissionCheckBundleId = bundleId;
viewPath.next();
if (viewPath.isEnd() || viewPath.isNextEnd()) {
if (bundleBeingViewed != bundleId) {
bundleBeingViewed = bundleId;
BundleCriteria criteria = new BundleCriteria();
criteria.addFilterId(bundleId);
criteria.fetchBundleVersions(true);
criteria.fetchDestinations(true);
criteria.fetchTags(true);
GWTServiceLookup.getBundleService().findBundlesByCriteria(criteria,
new AsyncCallback<PageList<Bundle>>() {
@Override
public void onFailure(Throwable caught) {
getErrorHandler().handleError(MSG.view_bundle_list_error3(), caught);
}
@Override
public void onSuccess(PageList<Bundle> result) {
if (result == null || result.isEmpty()) {
String conciseMessage = MSG.view_bundle_list_error4();
getMessageCenter().notify(new Message(conciseMessage, Message.Severity.Error));
return;
}
Bundle bundle = result.get(0);
viewBundle(bundle, viewPath.getCurrent());
}
});
} else if (!viewPath.isEnd()) {
String current = viewPath.getCurrent().getPath();
if ("versions".equals(current)) {
tabs.selectTab(versionsTab);
} else if ("destinations".equals(current)) {
tabs.selectTab(destinationsTab);
}
viewBundle(bundle, viewPath.getCurrent());
}
} else {
// Although still relevant the bundle is no longer being viewed. Set to 0 for re-fetch if needed
// also, destroy the current layout to make way for the new summary
bundleBeingViewed = 0;
this.destroyMembers();
if (viewPath.getCurrent().getPath().equals("versions")) {
if (!viewPath.isEnd()) {
// a specific version
BundleVersionView view = new BundleVersionView(canDelete, canDeploy, canTag);
addMember(view);
view.renderView(viewPath.next());
}
} else if (viewPath.getCurrent().getPath().equals("deployments")) {
// today we do not have an uber-view showing all deployments for a bundle.
// if we did, it would show all deployments to all destinations for all bundle versions.
// because that would be a very large list with a lot of stuff to show, it was deemed
// too complex to be useful for users. thus, we have no uber-deployments view. If we did,
// we would render it here.
if (!viewPath.isEnd()) {
// a specific deployment
//removeMembers(getMembers());
BundleDeploymentView view = new BundleDeploymentView(canDelete, canDeploy, canTag);
addMember(view);
view.renderView(viewPath.next());
}
} else if (viewPath.getCurrent().getPath().equals("destinations")) {
if (!viewPath.isEnd()) {
// a specific destination
BundleDestinationView view = new BundleDestinationView(canDelete, canDeploy, canTag);
addMember(view);
view.renderView(viewPath.next());
}
}
}
}
}