Beispiel #1
0
  private void fetchFavorites(
      Set<Integer> resourceIds,
      final Set<Integer> groupIds,
      final AsyncCallback<Favorites> callback) {

    ResourceCriteria criteria = new ResourceCriteria();
    criteria.addFilterIds(resourceIds.toArray(new Integer[resourceIds.size()]));
    GWTServiceLookup.getResourceService()
        .findResourcesByCriteria(
            criteria,
            new AsyncCallback<PageList<Resource>>() {
              public void onFailure(Throwable caught) {
                callback.onFailure(caught);
              }

              public void onSuccess(final PageList<Resource> resources) {

                if (groupIds.isEmpty()) {
                  callback.onSuccess(
                      new Favorites(resources, new PageList<ResourceGroupComposite>()));
                  return;
                }

                ResourceGroupCriteria criteria = new ResourceGroupCriteria();
                criteria.addFilterIds(groupIds.toArray(new Integer[groupIds.size()]));
                GWTServiceLookup.getResourceGroupService()
                    .findResourceGroupCompositesByCriteria(
                        criteria,
                        new AsyncCallback<PageList<ResourceGroupComposite>>() {
                          public void onFailure(Throwable caught) {
                            callback.onFailure(caught);
                          }

                          public void onSuccess(PageList<ResourceGroupComposite> groups) {
                            callback.onSuccess(new Favorites(resources, groups));
                          }
                        });
              }
            });
  }
  protected void lookupDetails(int historyId) {
    GroupOperationHistoryCriteria criteria = new GroupOperationHistoryCriteria();

    criteria.addFilterId(historyId);

    criteria.fetchOperationDefinition(true);
    criteria.fetchParameters(true);

    GWTServiceLookup.getOperationService()
        .findGroupOperationHistoriesByCriteria(
            criteria,
            new AsyncCallback<PageList<GroupOperationHistory>>() {
              public void onFailure(Throwable caught) {
                CoreGUI.getErrorHandler()
                    .handleError(MSG.view_operationHistoryDetails_error_fetchFailure(), caught);
              }

              public void onSuccess(PageList<GroupOperationHistory> result) {
                GroupOperationHistory groupOperationHistory = result.get(0);
                displayDetails(groupOperationHistory);
              }
            });
  }
  private void refreshSingletons(
      final Resource parentResource, final AsyncCallback<PageList<Resource>> callback) {
    singletonChildren = new ArrayList<Resource>(); // initialize to non-null

    Integer[] singletonChildTypes = getSingletonChildTypes(parentResource.getResourceType());

    if (canCreate && singletonChildTypes.length > 0 && (hasCreatableTypes || hasImportableTypes)) {
      ResourceCriteria criteria = new ResourceCriteria();
      criteria.addFilterParentResourceId(parentResource.getId());
      criteria.addFilterResourceTypeIds(singletonChildTypes);
      GWTServiceLookup.getResourceService()
          .findResourcesByCriteria(
              criteria,
              new AsyncCallback<PageList<Resource>>() {

                @Override
                public void onSuccess(PageList<Resource> result) {
                  singletonChildren = result;
                  if (callback != null) {
                    callback.onSuccess(result);
                  }
                }

                @Override
                public void onFailure(Throwable caught) {
                  Log.error("Failed to load child resources for [" + parentResource + "]", caught);
                  if (callback != null) {
                    callback.onFailure(caught);
                  }
                }
              });
    } else {
      if (callback != null) {
        callback.onSuccess(new PageList<Resource>());
      }
    }
  }
/** @author Greg Hinkle */
public class ContentRepositoryTreeDataSource extends RPCDataSource<Repo, RepoCriteria> {

  private RepoGWTServiceAsync repoService = GWTServiceLookup.getRepoService();

  public ContentRepositoryTreeDataSource() {
    super();
    List<DataSourceField> fields = addDataSourceFields();
    addFields(fields);
  }

  @Override
  protected List<DataSourceField> addDataSourceFields() {
    List<DataSourceField> fields = super.addDataSourceFields();

    DataSourceField idDataField = new DataSourceTextField("id", MSG.common_title_id());
    idDataField.setPrimaryKey(true);
    fields.add(idDataField);

    DataSourceTextField nameDataField = new DataSourceTextField("name", MSG.common_title_name());
    nameDataField.setCanEdit(false);
    fields.add(nameDataField);

    DataSourceTextField parentIdField =
        new DataSourceTextField("parentId", MSG.dataSource_ContentRepoTree_field_parentId());
    parentIdField.setForeignKey("id");
    fields.add(parentIdField);

    return fields;
  }

  @Override
  protected void executeFetch(
      final DSRequest request, final DSResponse response, final RepoCriteria criteria) {
    repoService.findReposByCriteria(
        criteria,
        new AsyncCallback<PageList<Repo>>() {
          public void onFailure(Throwable caught) {
            CoreGUI.getErrorHandler()
                .handleError(MSG.dataSource_ContentRepoTree_error_load(), caught);
          }

          public void onSuccess(PageList<Repo> result) {
            response.setData(buildRecords(result));
            processResponse(request.getRequestId(), response);
          }
        });
  }

  @Override
  protected RepoCriteria getFetchCriteria(final DSRequest request) {
    RepoCriteria criteria = new RepoCriteria();
    return criteria;
  }

  @Override
  public Repo copyValues(Record from) {
    return null; // TODO: Implement this method.
  }

  @Override
  public ListGridRecord copyValues(Repo from) {
    TreeNode record = new TreeNode();

    record.setID(String.valueOf(from.getId()));
    record.setName(from.getName());

    record.setAttribute("id", from.getId());
    record.setAttribute("name", from.getName());
    record.setAttribute("description", from.getDescription());
    record.setAttribute("syncSchedule", from.getSyncSchedule());
    record.setAttribute("syncStatus", from.getSyncStatus());

    record.setIsFolder(false); // don't attempt to load any children

    return record;
  }
}
/** @author Joseph Marques */
public class ResourceGroupCompositeDataSource
    extends RPCDataSource<ResourceGroupComposite, ResourceGroupCriteria> {

  private static final Messages MSG = CoreGUI.getMessages();

  public static final String FILTER_GROUP_IDS = "resourceGroupIds";

  ResourceGroupGWTServiceAsync groupService = GWTServiceLookup.getResourceGroupService();

  private static ResourceGroupCompositeDataSource INSTANCE;

  public static ResourceGroupCompositeDataSource getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new ResourceGroupCompositeDataSource();
    }
    return INSTANCE;
  }

  public ResourceGroupCompositeDataSource() {
    super();
    List<DataSourceField> fields = addDataSourceFields();
    addFields(fields);
  }

  @Override
  protected List<DataSourceField> addDataSourceFields() {
    List<DataSourceField> fields = super.addDataSourceFields();

    DataSourceField idDataField = new DataSourceIntegerField("id", MSG.common_title_id(), 50);
    idDataField.setPrimaryKey(true);
    idDataField.setCanEdit(false);
    fields.add(idDataField);

    DataSourceTextField nameDataField =
        new DataSourceTextField(NAME.propertyName(), NAME.title(), 200);
    nameDataField.setCanEdit(false);
    fields.add(nameDataField);

    DataSourceTextField descriptionDataField =
        new DataSourceTextField(DESCRIPTION.propertyName(), DESCRIPTION.title());
    descriptionDataField.setCanEdit(false);
    fields.add(descriptionDataField);

    DataSourceTextField typeNameDataField =
        new DataSourceTextField(TYPE.propertyName(), TYPE.title());
    fields.add(typeNameDataField);

    DataSourceTextField pluginNameDataField =
        new DataSourceTextField(PLUGIN.propertyName(), PLUGIN.title());
    fields.add(pluginNameDataField);

    DataSourceTextField categoryDataField =
        new DataSourceTextField(CATEGORY.propertyName(), CATEGORY.title());
    fields.add(categoryDataField);

    return fields;
  }

  @Override
  public void executeFetch(
      final DSRequest request, final DSResponse response, final ResourceGroupCriteria criteria) {
    groupService.findResourceGroupCompositesByCriteria(
        criteria,
        new AsyncCallback<PageList<ResourceGroupComposite>>() {
          public void onFailure(Throwable caught) {
            if (caught.getMessage().contains("SearchExpressionException")) {
              Message message =
                  new Message(MSG.view_searchBar_suggest_noSuggest(), Message.Severity.Error);
              CoreGUI.getMessageCenter().notify(message);
            } else {
              CoreGUI.getErrorHandler().handleError(MSG.view_inventory_groups_loadFailed(), caught);
            }
            response.setStatus(RPCResponse.STATUS_FAILURE);
            processResponse(request.getRequestId(), response);
          }

          private PageList<ResourceGroupComposite> applyAvailabilitySearchFilter(
              PageList<ResourceGroupComposite> result) {

            if (!isAvailabilitySearch(criteria)) {
              return result;
            }
            PageList<ResourceGroupComposite> pageList =
                new PageList<ResourceGroupComposite>(result.getPageControl());

            for (ResourceGroupComposite rgc : result) {
              if (rgc.getExplicitCount() > 0) {
                pageList.add(rgc);
              }
            }

            return pageList;
          }

          public void onSuccess(PageList<ResourceGroupComposite> result) {
            PageList<ResourceGroupComposite> filteredResult = applyAvailabilitySearchFilter(result);
            response.setData(buildRecords(filteredResult));
            setPagingInfo(response, result);
            processResponse(request.getRequestId(), response);
          }
        });
  }

  private boolean isAvailabilitySearch(ResourceGroupCriteria criteria) {
    return criteria.getSearchExpression() != null
        && criteria.getSearchExpression().startsWith("availability");
  }

  @Override
  protected ResourceGroupCriteria getFetchCriteria(final DSRequest request) {
    ResourceGroupCriteria criteria = new ResourceGroupCriteria();

    criteria.addFilterId(getFilter(request, "id", Integer.class));
    criteria.addFilterName(getFilter(request, NAME.propertyName(), String.class));
    criteria.addFilterGroupCategory(
        getFilter(request, CATEGORY.propertyName(), GroupCategory.class));
    criteria.addFilterDownMemberCount(getFilter(request, "downMemberCount", Long.class));
    criteria.addFilterExplicitResourceIds(getFilter(request, "explicitResourceId", Integer.class));
    criteria.addFilterGroupDefinitionId(getFilter(request, "groupDefinitionId", Integer.class));
    criteria.setSearchExpression(getFilter(request, "search", String.class));
    criteria.addFilterIds(getArrayFilter(request, FILTER_GROUP_IDS, Integer.class));

    return criteria;
  }

  @Override
  public ResourceGroupComposite copyValues(Record from) {
    Integer idAttrib = from.getAttributeAsInt("id");
    String nameAttrib = from.getAttribute(NAME.propertyName());
    String descriptionAttrib = from.getAttribute(DESCRIPTION.propertyName());
    String typeNameAttrib = from.getAttribute(TYPE.propertyName());

    ResourceGroup rg = new ResourceGroup(nameAttrib);
    rg.setId(idAttrib);
    rg.setDescription(descriptionAttrib);
    if (typeNameAttrib != null) {
      ResourceType rt = new ResourceType();
      rt.setName(typeNameAttrib);
      String pluginNameAttrib = from.getAttribute(PLUGIN.propertyName());
      rt.setPlugin(pluginNameAttrib);
      rg.setResourceType(rt);
    }

    Long explicitCount = Long.valueOf(from.getAttribute("explicitCount"));
    Long explicitDown = Long.valueOf(from.getAttribute("explicitDown"));
    Long explicitUnknown = Long.valueOf(from.getAttribute("explicitUnknown"));
    Long explicitDisabled = Long.valueOf(from.getAttribute("explicitDisabled"));
    Long implicitCount = Long.valueOf(from.getAttribute("implicitCount"));
    Long implicitDown = Long.valueOf(from.getAttribute("implicitDown"));
    Long implicitUnknown = Long.valueOf(from.getAttribute("implicitUnknown"));
    Long implicitDisabled = Long.valueOf(from.getAttribute("implicitDisabled"));

    ResourceGroupComposite composite =
        new ResourceGroupComposite(
            explicitCount,
            explicitDown,
            explicitUnknown,
            explicitDisabled,
            implicitCount,
            implicitDown,
            implicitUnknown,
            implicitDisabled,
            rg);

    return composite;
  }

  @Override
  public ListGridRecord copyValues(ResourceGroupComposite from) {
    ListGridRecord record = new ListGridRecord();
    record.setAttribute("group", from);
    record.setAttribute("id", from.getResourceGroup().getId());
    record.setAttribute(NAME.propertyName(), from.getResourceGroup().getName());
    record.setAttribute(DESCRIPTION.propertyName(), from.getResourceGroup().getDescription());
    record.setAttribute(CATEGORY.propertyName(), from.getResourceGroup().getGroupCategory().name());

    record.setAttribute("explicitCount", String.valueOf(from.getExplicitCount()));
    record.setAttribute("explicitDown", String.valueOf(from.getExplicitDown()));
    record.setAttribute("explicitDisabled", String.valueOf(from.getExplicitDisabled()));
    record.setAttribute("implicitCount", String.valueOf(from.getImplicitCount()));
    record.setAttribute("implicitDown", String.valueOf(from.getImplicitDown()));
    record.setAttribute("implicitDisabled", String.valueOf(from.getImplicitDisabled()));

    record.setAttribute(AVAIL_CHILDREN.propertyName(), getExplicitFormatted(from));
    record.setAttribute(AVAIL_DESCENDANTS.propertyName(), getImplicitFormatted(from));

    if (from.getResourceGroup().getResourceType() != null) {
      record.setAttribute("resourceType", from.getResourceGroup().getResourceType());
      record.setAttribute(TYPE.propertyName(), from.getResourceGroup().getResourceType().getName());
      record.setAttribute(
          PLUGIN.propertyName(), from.getResourceGroup().getResourceType().getPlugin());
    }

    return record;
  }

  private String getExplicitFormatted(ResourceGroupComposite from) {
    return getAlignedAvailabilityResults(
        from.getExplicitCount(),
        from.getExplicitUp(),
        from.getExplicitDown(),
        from.getExplicitUnknown(),
        from.getExplicitDisabled());
  }

  private String getImplicitFormatted(ResourceGroupComposite from) {
    return getAlignedAvailabilityResults(
        from.getImplicitCount(),
        from.getImplicitUp(),
        from.getImplicitDown(),
        from.getImplicitUnknown(),
        from.getImplicitDisabled());
  }

  private String getAlignedAvailabilityResults(
      long total, long up, long down, long unknown, long disabled) {
    StringBuilder results = new StringBuilder();

    results.append("<table><tr>");
    if (0 == total) {
      results.append(
          getColumn(
              false,
              "<img height=\"12\" width=\"12\" src=\""
                  + ImageManager.getFullImagePath(ImageManager.getAvailabilityIcon(null))
                  + "\" /> 0"));
      results.append(getColumn(true));
      results.append(getColumn(false));

    } else {
      if (up > 0) {
        String imagePath =
            ImageManager.getFullImagePath(
                ImageManager.getAvailabilityIconFromAvailType(AvailabilityType.UP));
        results.append(
            getColumn(false, " <img height=\"12\" width=\"12\" src=\"" + imagePath + "\" />", up));
      } else {
        results.append(
            getColumn(
                false,
                "&nbsp;<img src=\""
                    + ImageManager.getBlankIcon()
                    + "\" width=\"12px\" height=\"12px\" />"));
      }

      if (down > 0) {
        String imagePath =
            ImageManager.getFullImagePath(
                ImageManager.getAvailabilityIconFromAvailType(AvailabilityType.DOWN));
        results.append(
            getColumn(
                false, " <img height=\"12\" width=\"12\" src=\"" + imagePath + "\" />", down));
      } else {
        results.append(
            getColumn(
                false,
                "&nbsp;<img src=\""
                    + ImageManager.getBlankIcon()
                    + "\" width=\"12px\" height=\"12px\" />"));
      }

      if (disabled > 0) {
        String imagePath =
            ImageManager.getFullImagePath(
                ImageManager.getAvailabilityIconFromAvailType(AvailabilityType.DISABLED));
        results.append(
            getColumn(
                false, " <img height=\"12\" width=\"12\" src=\"" + imagePath + "\" />", disabled));
      } else {
        results.append(
            getColumn(
                false,
                "&nbsp;<img src=\""
                    + ImageManager.getBlankIcon()
                    + "\" width=\"12px\" height=\"12px\" />"));
      }

      if (unknown > 0) {
        String imagePath =
            ImageManager.getFullImagePath(
                ImageManager.getAvailabilityIconFromAvailType(AvailabilityType.UNKNOWN));
        results.append(
            getColumn(
                false, " <img height=\"12\" width=\"12\" src=\"" + imagePath + "\" />", unknown));
      } else {
        results.append(
            getColumn(
                false,
                "&nbsp;<img src=\""
                    + ImageManager.getBlankIcon()
                    + "\" width=\"1px\" height=\"1px\" />"));
      }
    }
    results.append("</tr></table>");
    return results.toString();
  }

  private String getColumn(boolean isSpacerColumn, Object... data) {
    StringBuilder results = new StringBuilder();
    if (isSpacerColumn) {
      results.append(
          "<td nowrap=\"nowrap\" style=\"white-space:nowrap;\" width=\"10px\" align=\"left\" >");
    } else {
      results.append(
          "<td nowrap=\"nowrap\" style=\"white-space:nowrap;\" width=\"45px\" align=\"left\" >");
    }
    if (data == null) {
      results.append("&nbsp;");
    } else {
      for (Object datum : data) {
        results.append(datum == null ? "&nbsp;" : datum);
      }
    }
    results.append("</td>");
    return results.toString();
  }
}
Beispiel #6
0
/** @author Greg Hinkle */
public class RemoteAgentInstallView extends EnhancedVLayout {
  public static final ViewName VIEW_ID =
      new ViewName(
          "RemoteAgentInstall", MSG.view_adminTopology_remoteAgentInstall(), IconEnum.AGENT);

  private RemoteInstallGWTServiceAsync remoteInstallService =
      GWTServiceLookup.getRemoteInstallService(600000);

  private DynamicForm connectionForm;
  private Layout buttonsForm;
  private EnhancedIButton installButton;
  private EnhancedIButton uninstallButton;
  private EnhancedIButton startButton;
  private EnhancedIButton stopButton;
  private TextItem agentInstallPath;
  private StaticTextItem agentStatusText;
  private ButtonItem findAgentInstallPathButton;
  private ButtonItem statusCheckButton;
  private CheckboxItem rememberMeCheckbox;

  private Dialog dialog;

  private final boolean showInstallButton;
  private final boolean showUninstallButton;
  private final boolean showStartButton;
  private final boolean showStopButton;

  private AgentInstall initialAgentInstall;

  private SuccessHandler successHandler = null;

  // for installing agents, these are the components to work with uploading config files for the new
  // agent to use
  private FileUploadForm agentConfigXmlUploadForm;
  private FileUploadForm rhqAgentEnvUploadForm;
  private String agentConfigurationXml = null;
  private String rhqAgentEnvSh = null;

  private final AbsolutePathValidator absPathValidator = new AbsolutePathValidator();

  // if the user has explicitly authorized the unknown host
  private boolean hostAuthorized = false;

  public static enum Type {
    INSTALL,
    UNINSTALL,
    START,
    STOP;
  }

  public RemoteAgentInstallView(AgentInstall initialInfo, Type type) {
    super();
    setMembersMargin(1);
    setWidth100();
    setHeight100();

    this.initialAgentInstall = initialInfo;
    this.showInstallButton = (type == Type.INSTALL);
    this.showUninstallButton = (type == Type.UNINSTALL);
    this.showStartButton = (type == Type.START);
    this.showStopButton = (type == Type.STOP);
  }

  @Override
  protected void onInit() {
    super.onInit();
    Layout layout = new VLayout();
    layout.setPadding(5);
    layout.setMembersMargin(5);
    layout.addMember(getConnectionForm());
    layout.setDefaultLayoutAlign(Alignment.CENTER);
    layout.setLayoutAlign(Alignment.CENTER);

    if (this.showInstallButton) {
      agentConfigXmlUploadForm = createAgentConfigXmlUploadForm();
      layout.addMember(agentConfigXmlUploadForm);
      /* For now, don't allow users to upload and ship their own env script to a remote machine; that might have security implications.
       * If we want to allow this, just uncomment these lines and you are good to go because everything else that is needed
       * is already in place and working as of April 2014.
      rhqAgentEnvUploadForm = createAgentEnvUploadForm();
      layout.addMember(rhqAgentEnvUploadForm);
      */
    }

    HTMLFlow header = new HTMLFlow("");
    header.setStyleName("headerItem");
    header.setExtraSpace(5);
    layout.addMember(header);
    layout.addMember(getButtons());

    addMember(layout);
  }

  private DynamicForm getConnectionForm() {
    connectionForm = new DynamicForm();
    connectionForm.setNumCols(4);
    connectionForm.setWrapItemTitles(false);
    connectionForm.setColWidths("130", "450", "110");
    connectionForm.setExtraSpace(15);
    connectionForm.setWidth(790);
    connectionForm.setPadding(5);
    connectionForm.setIsGroup(true);
    connectionForm.setGroupTitle(MSG.view_remoteAgentInstall_connInfo());
    final int textFieldWidth = 440;

    TextItem host = new TextItem("host", MSG.common_title_host());
    host.setRequired(true);
    host.setWidth(textFieldWidth);
    host.setPrompt(MSG.view_remoteAgentInstall_promptHost());
    host.setHoverWidth(300);
    host.setEndRow(true);
    host.addChangedHandler(
        new ChangedHandler() {
          @Override
          public void onChanged(ChangedEvent event) {
            hostAuthorized =
                false; // if the host changes, we need to make sure the user authorizes it if needed
          }
        });

    TextItem port = new TextItem("port", MSG.common_title_port());
    port.setRequired(false);
    port.setWidth(textFieldWidth);
    port.setPrompt(MSG.view_remoteAgentInstall_promptPort());
    port.setHoverWidth(300);
    port.setEndRow(true);
    IntegerRangeValidator portValidator = new IntegerRangeValidator();
    portValidator.setMin(1);
    portValidator.setMax(65535);
    port.setValidators(new IsIntegerValidator(), portValidator);

    TextItem username = new TextItem("username", MSG.common_title_user());
    username.setRequired(
        false); // if not specified, the server will attempt to use the default ssh user defined in
                // system settings
    username.setWidth(textFieldWidth);
    username.setPrompt(MSG.view_remoteAgentInstall_promptUser());
    username.setHoverWidth(300);
    username.setEndRow(true);

    PasswordItem password = new PasswordItem("password", MSG.common_title_password());
    password.setRequired(
        false); // if not specified, the server will attempt to use the default ssh pw defined in
                // system settings
    password.setWidth(textFieldWidth);
    password.setPrompt(MSG.view_remoteAgentInstall_promptPassword());
    password.setHoverWidth(300);
    password.setEndRow(true);
    password.setAttribute("autocomplete", "off");

    rememberMeCheckbox = new CheckboxItem("rememberme", MSG.view_remoteAgentInstall_rememberMe());
    rememberMeCheckbox.setRequired(false);
    rememberMeCheckbox.setPrompt(MSG.view_remoteAgentInstall_promptRememberMe());
    rememberMeCheckbox.setHoverWidth(300);
    rememberMeCheckbox.setColSpan(2);
    rememberMeCheckbox.setEndRow(true);

    agentInstallPath = new TextItem("agentInstallPath", MSG.view_remoteAgentInstall_installPath());
    agentInstallPath.setWidth(textFieldWidth);
    agentInstallPath.setPrompt(MSG.view_remoteAgentInstall_promptInstallPath());
    agentInstallPath.setHoverWidth(300);
    agentInstallPath.setStartRow(true);
    agentInstallPath.setEndRow(false);
    agentInstallPath.setValidators(
        absPathValidator); // we will "turn this on" when needed - this is to ensure we create paths
                           // properly and it doesn't go in places user isn't expecting

    findAgentInstallPathButton =
        new ButtonItem("findAgentInstallPathButton", MSG.view_remoteAgentInstall_buttonFindAgent());
    findAgentInstallPathButton.setStartRow(false);
    findAgentInstallPathButton.setEndRow(true);
    if (findAgentInstallPathButton.getTitle().length() < 15) { // i18n may prolong the title
      findAgentInstallPathButton.setWidth(100);
    }
    findAgentInstallPathButton.addClickHandler(
        new com.smartgwt.client.widgets.form.fields.events.ClickHandler() {
          public void onClick(
              com.smartgwt.client.widgets.form.fields.events.ClickEvent clickEvent) {
            // we only want to validate host
            if (connectionForm.getValueAsString("host") == null
                || connectionForm.getValueAsString("host").trim().isEmpty()) {
              final HashMap<String, String> errors = new HashMap<String, String>(1);
              errors.put("host", CoreGUI.getSmartGwtMessages().validator_requiredField());
              connectionForm.setErrors(errors, true);
              return;
            }

            new CheckSSHConnectionCallback() {
              @Override
              protected void doActualWork() {
                findAgentInstallPath();
              }
            }.execute();
          }
        });

    createAgentStatusTextItem();

    statusCheckButton = new ButtonItem("updateStatus", MSG.common_title_updateStatus());
    statusCheckButton.setStartRow(false);
    statusCheckButton.setEndRow(true);
    if (findAgentInstallPathButton.getTitle().length() < 15) { // i18n may prolong the title
      statusCheckButton.setWidth(100);
    }
    statusCheckButton.addClickHandler(
        new com.smartgwt.client.widgets.form.fields.events.ClickHandler() {
          public void onClick(
              com.smartgwt.client.widgets.form.fields.events.ClickEvent clickEvent) {
            if (connectionForm.validate()) {
              new CheckSSHConnectionCallback() {
                @Override
                protected void doActualWork() {
                  agentStatusCheck();
                }
              }.execute();
            }
          }
        });

    if (initialAgentInstall != null) {
      host.setValue(initialAgentInstall.getSshHost());
      if (initialAgentInstall.getSshPort() != null) {
        port.setValue(String.valueOf(initialAgentInstall.getSshPort()));
      }
      username.setValue(initialAgentInstall.getSshUsername());
      password.setValue(initialAgentInstall.getSshPassword());
      agentInstallPath.setValue(initialAgentInstall.getInstallLocation());
      // if it was already saved, assume they want it to stay remembered
      // however, because the uninstall page is getting rid of the agent, we don't need or want to
      // remember the credentials anymore
      if (!this.showUninstallButton) {
        rememberMeCheckbox.setValue(initialAgentInstall.getSshPassword() != null);
      }
    }

    // disable some form elements if we don't want the user changing them - they should have been
    // filled in by who ever created this view
    if (this.showUninstallButton || this.showStartButton || this.showStopButton) {
      host.setDisabled(true);
      port.setDisabled(true);
      agentInstallPath.setDisabled(true);
      findAgentInstallPathButton.setDisabled(true);
    }

    if (this.showUninstallButton) {
      // don't show rememberMe checkbox - we're getting rid of this agent so there won't be a record
      // to store the creds
      connectionForm.setFields(
          host,
          port,
          username,
          password,
          agentInstallPath,
          findAgentInstallPathButton,
          agentStatusText,
          statusCheckButton);
    } else {
      connectionForm.setFields(
          host,
          port,
          username,
          password,
          rememberMeCheckbox,
          agentInstallPath,
          findAgentInstallPathButton,
          agentStatusText,
          statusCheckButton);
    }

    return connectionForm;
  }

  private void createAgentStatusTextItem() {
    agentStatusText = new StaticTextItem("agentStatus", MSG.view_remoteAgentInstall_agentStatus());
    agentStatusText.setDefaultValue(MSG.view_remoteAgentInstall_agentStatusDefault());
    agentStatusText.setRedrawOnChange(true);
    agentStatusText.setStartRow(true);
    agentStatusText.setEndRow(false);
  }

  private Layout getButtons() {
    buttonsForm = new HLayout();

    installButton = new EnhancedIButton(MSG.view_remoteAgentInstall_installAgent());
    installButton.setExtraSpace(10);
    installButton.addClickHandler(
        new ClickHandler() {
          public void onClick(ClickEvent clickEvent) {
            absPathValidator.setPerformCheck(true);
            try {
              if (connectionForm.validate()) {
                new CheckSSHConnectionCallback() {
                  @Override
                  protected void doActualWork() {
                    installAgent();
                  }
                }.execute();
              }
            } finally {
              absPathValidator.setPerformCheck(false);
            }
          }
        });

    uninstallButton = new EnhancedIButton(MSG.view_remoteAgentInstall_uninstallAgent());
    uninstallButton.setExtraSpace(10);
    uninstallButton.addClickHandler(
        new ClickHandler() {
          public void onClick(ClickEvent clickEvent) {
            absPathValidator.setPerformCheck(true);
            try {
              if (connectionForm.validate()) {
                new CheckSSHConnectionCallback() {
                  @Override
                  protected void doActualWork() {
                    uninstallAgent();
                  }
                }.execute();
              }
            } finally {
              absPathValidator.setPerformCheck(false);
            }
          }
        });

    startButton = new EnhancedIButton(MSG.common_label_startAgent());
    startButton.setExtraSpace(10);
    startButton.addClickHandler(
        new ClickHandler() {
          public void onClick(ClickEvent clickEvent) {
            if (connectionForm.validate()) {
              new CheckSSHConnectionCallback() {
                @Override
                protected void doActualWork() {
                  startAgent();
                }
              }.execute();
            }
          }
        });

    stopButton = new EnhancedIButton(MSG.view_remoteAgentInstall_stopAgent());
    stopButton.setExtraSpace(10);
    stopButton.addClickHandler(
        new ClickHandler() {
          public void onClick(ClickEvent clickEvent) {
            if (connectionForm.validate()) {
              new CheckSSHConnectionCallback() {
                @Override
                protected void doActualWork() {
                  stopAgent();
                }
              }.execute();
            }
          }
        });

    ArrayList<Canvas> buttons = new ArrayList<Canvas>(3);
    if (this.showInstallButton) {
      buttons.add(installButton);
    }
    if (this.showUninstallButton
        && initialAgentInstall != null
        && initialAgentInstall.getAgentName() != null) {
      buttons.add(
          uninstallButton); // note we only show this if we were given the agent name because that
                            // is required to be known to uninstall
    }
    if (this.showStartButton) {
      buttons.add(startButton);
    }
    if (this.showStopButton) {
      buttons.add(stopButton);
    }

    if (buttons.size() > 0) {
      buttonsForm.setAlign(Alignment.CENTER);
      buttonsForm.setMembers(buttons.toArray(new Canvas[buttons.size()]));
    }

    return buttonsForm;
  }

  /**
   * Call this method when we know all processing (including all async calls) are done and we are
   * ready for the user to interact with the page again.
   */
  private void doneProcessing() {
    disableButtons(false);
    hostAuthorized =
        false; // if the ssh fingerprint changes under us this forces the user to re-authorize again
    dialog.markForDestroy();
  }

  private void displayError(String msg) {
    displayError(msg, null);
  }

  private void displayError(String msg, Throwable caught) {
    CoreGUI.getErrorHandler().handleError(msg, caught);
    String rootCause = ErrorHandler.getRootCauseMessage(caught);

    // JSch returns very bad error messages, transform them here before returning to the customer
    String fullMsg = null;
    if (rootCause != null && msg != null) {
      String runtimeException = "java.lang.RuntimeException";
      if ("com.jcraft.jsch.JSchException:Auth cancel".equals(rootCause)) {
        fullMsg = MSG.view_remoteAgentInstall_error_authFailed();
      } else if (rootCause.indexOf("java.net.UnknownHostException") != -1) {
        fullMsg = MSG.view_remoteAgentInstall_error_unknownHost();
      } else if ("java.net.ConnectException:Connection refused".equals(rootCause)) {
        fullMsg = MSG.view_remoteAgentInstall_error_connRefused();
      } else if (rootCause.indexOf(runtimeException) != -1) {
        int exceptionEnd =
            rootCause.indexOf(runtimeException) + runtimeException.length() + 1; // remove : also
        fullMsg = rootCause.substring(exceptionEnd);
      }
    }

    // Fallback
    if (fullMsg == null) {
      fullMsg = (rootCause == null) ? msg : msg + ": " + rootCause;
    }
    SC.warn(fullMsg);
  }

  private void displayMessage(String msg) {
    CoreGUI.getMessageCenter()
        .notify(
            new Message(
                msg, Message.Severity.Info, EnumSet.of(Message.Option.BackgroundJobResult)));
  }

  private void setAgentStatusText(String msg) {
    if (agentStatusText != null) {
      agentStatusText.setValue(msg);
    }
  }

  private FileUploadForm createAgentConfigXmlUploadForm() {
    final FileUploadForm uploadForm =
        new FileUploadForm("agent-configuration.xml", "1", false, true, null, true);
    uploadForm.setCustomTooltipMessage(MSG.view_remoteAgentInstall_promptAgentConfigXml());
    uploadForm.setAutoWidth();
    uploadForm.setPadding(5);
    uploadForm.setIsGroup(true);
    uploadForm.setGroupTitle("agent-configuration.xml");

    uploadForm.addFormHandler(
        new DynamicFormHandler() {
          @Override
          public void onSubmitComplete(DynamicFormSubmitCompleteEvent event) {
            List<String> paths = uploadForm.getUploadedFilePaths();
            if (paths != null && paths.size() == 1) {
              agentConfigurationXml = paths.get(0);
            } else {
              agentConfigurationXml = null;
            }
          }
        });
    return uploadForm;
  }

  private FileUploadForm createAgentEnvUploadForm() {
    final FileUploadForm uploadForm =
        new FileUploadForm("rhq-agent-env.sh", "1", false, true, null, true);
    uploadForm.setCustomTooltipMessage(MSG.view_remoteAgentInstall_promptRhqAgentEnv());
    uploadForm.setAutoWidth();
    uploadForm.setPadding(5);
    uploadForm.setIsGroup(true);
    uploadForm.setGroupTitle("rhq-agent-env.sh");
    uploadForm.addFormHandler(
        new DynamicFormHandler() {
          @Override
          public void onSubmitComplete(DynamicFormSubmitCompleteEvent event) {
            List<String> paths = uploadForm.getUploadedFilePaths();
            if (paths != null && paths.size() == 1) {
              rhqAgentEnvSh = paths.get(0);
            } else {
              rhqAgentEnvSh = null;
            }
          }
        });
    return uploadForm;
  }

  private void findAgentInstallPath() {
    disableButtons(true);

    final String parentPath = getAgentInstallPath();

    createWaitingWindow(MSG.view_remoteAgentInstall_findAgentWait(), true);

    remoteInstallService.findAgentInstallPath(
        getRemoteAccessInfo(),
        parentPath,
        new AsyncCallback<String>() {
          public void onFailure(Throwable caught) {
            displayError(MSG.view_remoteAgentInstall_error_1(), caught);
            doneProcessing();
          }

          public void onSuccess(String result) {
            if (result != null) {
              agentInstallPath.setValue(result);
              agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't
                                  // do it here
            } else {
              String err;
              if (parentPath == null || parentPath.length() == 0) {
                err = MSG.view_remoteAgentInstall_error_2();
              } else {
                err = MSG.view_remoteAgentInstall_error_3(parentPath);
              }
              displayError(err, null);
              setAgentStatusText(MSG.view_remoteAgentInstall_agentStatusDefault());
              doneProcessing();
            }
          }
        });
  }

  private void agentStatusCheck() {
    disableButtons(true);
    remoteInstallService.agentStatus(
        getRemoteAccessInfo(),
        getAgentInstallPath(),
        new AsyncCallback<String>() {
          public void onFailure(Throwable caught) {
            setAgentStatusText(caught.getMessage());
            doneProcessing();
          }

          public void onSuccess(String result) {
            setAgentStatusText(result);
            doneProcessing();
          }
        });
  }

  private void createWaitingWindow(String text, boolean show) {
    dialog = new Dialog();
    dialog.setMessage(text);
    dialog.setIcon("[SKIN]notify.png");
    dialog.draw();
    dialog.setTitle(MSG.view_remoteAgentInstall_dialogTitle());
    dialog.setShowCloseButton(false);
  }

  private void installAgent() {
    disableButtons(true);

    // FOR TESTING WITHOUT DOING A REAL INSTALL - START
    //        AgentInstallInfo result = new AgentInstallInfo("mypath", "myown", "1.1", "localHOST",
    // "serverHOST");
    //        for (int i = 1; i < 20; i++)
    //            result.addStep(new AgentInstallStep("cmd" + i, "desc" + i, i, "result" + i, i *
    // 10));
    //        for (Canvas child : agentInfoLayout.getChildren())
    //            child.destroy();
    //        buildInstallInfoCanvas(agentInfoLayout, result);
    //        agentInfoLayout.markForRedraw();
    //        disableButtons(false);
    //        if (true)
    //            return;
    // FOR TESTING WITHOUT DOING A REAL INSTALL - END

    // help out the user here - if they selected file(s) but didn't upload them yet, press the
    // upload button(s) for him
    // Note that if the user didn't upload yet, we have to wait for it to complete and ask the user
    // to press install again
    boolean needToWaitForUpload = false;
    if (agentConfigXmlUploadForm != null
        && agentConfigXmlUploadForm.isFileSelected()
        && agentConfigurationXml == null) {
      if (!agentConfigXmlUploadForm.isUploadInProgress()) {
        agentConfigXmlUploadForm.submitForm();
      }
      needToWaitForUpload = true;
    }
    if (rhqAgentEnvUploadForm != null
        && rhqAgentEnvUploadForm.isFileSelected()
        && rhqAgentEnvSh == null) {
      if (!rhqAgentEnvUploadForm.isUploadInProgress()) {
        rhqAgentEnvUploadForm.submitForm();
      }
      needToWaitForUpload = true;
    }

    if (!needToWaitForUpload) {
      reallyInstallAgent();
      return;
    }

    createWaitingWindow(MSG.view_remoteAgentInstall_waitForUpload(), true);

    Scheduler.get()
        .scheduleEntry(
            new RepeatingCommand() {
              @Override
              public boolean execute() {
                // Make sure the file upload(s) (if there are any) have completed before we do
                // anything
                boolean waitForUploadToFinish = false;
                if (agentConfigXmlUploadForm != null
                    && agentConfigXmlUploadForm.isUploadInProgress()) {
                  waitForUploadToFinish = true;
                }
                if (rhqAgentEnvUploadForm != null && rhqAgentEnvUploadForm.isUploadInProgress()) {
                  waitForUploadToFinish = true;
                }
                if (waitForUploadToFinish) {
                  return true; // keep waiting, call us back later
                }

                dialog.destroy();
                reallyInstallAgent();
                return false; // upload is done, we can stop calling ourselves
              }
            });
  }

  private void reallyInstallAgent() {
    disableButtons(true);
    setAgentStatusText(MSG.view_remoteAgentInstall_installingPleaseWait());

    createWaitingWindow(MSG.view_remoteAgentInstall_installingPleaseWait(), true);

    SC.ask(
        MSG.view_remoteAgentInstall_overwriteAgentTitle(),
        MSG.view_remoteAgentInstall_overwriteAgentQuestion(),
        new BooleanCallback() {
          @Override
          public void execute(Boolean overwriteExistingAgent) {
            CustomAgentInstallData customData =
                new CustomAgentInstallData(
                    getAgentInstallPath(),
                    overwriteExistingAgent.booleanValue(),
                    agentConfigurationXml); // , rhqAgentEnvSh);
            remoteInstallService.installAgent(
                getRemoteAccessInfo(),
                customData,
                new AsyncCallback<AgentInstallInfo>() {
                  public void onFailure(Throwable caught) {
                    displayError(MSG.view_remoteAgentInstall_error_4(), caught);
                    setAgentStatusText(MSG.view_remoteAgentInstall_error_4());

                    if (agentConfigXmlUploadForm != null) {
                      agentConfigXmlUploadForm.reset();
                    }
                    if (rhqAgentEnvUploadForm != null) {
                      rhqAgentEnvUploadForm.reset();
                    }
                    doneProcessing();
                  }

                  public void onSuccess(AgentInstallInfo result) {
                    // if the install button isn't created, user must have navigated away, so skip
                    // the UI stuff
                    if (installButton.isCreated()) {
                      installButton.setDisabled(
                          true); // don't re-enable install - install was successful, no need to do
                                 // it again

                      displayMessage(MSG.view_remoteAgentInstall_success());
                      setAgentStatusText(MSG.view_remoteAgentInstall_success());

                      if (!result.isConfirmedAgentConnection()) {
                        displayError(
                            MSG.view_remoteAgentInstall_error_cannotPingAgent(
                                result.getAgentAddress(), String.valueOf(result.getAgentPort())));
                      }

                      buildInstallInfoCanvas(result);
                      agentStatusCheck(); // we are relying on this to call doneProcessing(), we
                                          // shouldn't do it here
                    }

                    // tell the success handler
                    invokeSuccessHandler(Type.INSTALL);
                  }
                });
          }
        });
  }

  private void uninstallAgent() {
    disableButtons(true);

    createWaitingWindow(MSG.view_remoteAgentInstall_uninstallingPleaseWait(), true);

    remoteInstallService.uninstallAgent(
        getRemoteAccessInfo(),
        getAgentInstallPath(),
        new AsyncCallback<String>() {
          public void onFailure(Throwable caught) {
            displayError(MSG.view_remoteAgentInstall_error_7(), caught);
            setAgentStatusText(MSG.view_remoteAgentInstall_error_7());
            doneProcessing();
          }

          public void onSuccess(String result) {
            if (result != null) {
              setAgentStatusText(MSG.view_remoteAgentInstall_uninstallSuccess());
              displayMessage(MSG.view_remoteAgentInstall_uninstallAgentResults(result));
              agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't
                                  // do it here

              // tell the success handler
              invokeSuccessHandler(Type.UNINSTALL);
            } else {
              setAgentStatusText(MSG.view_remoteAgentInstall_error_7());
              doneProcessing();
            }
          }
        });
  }

  private void startAgent() {
    disableButtons(true);
    createWaitingWindow(MSG.view_remoteAgentInstall_startAgentPleaseWait(), true);
    remoteInstallService.startAgent(
        getRemoteAccessInfo(),
        getAgentInstallPath(),
        new AsyncCallback<String>() {
          public void onFailure(Throwable caught) {
            displayError(MSG.view_remoteAgentInstall_error_5(), caught);
            doneProcessing();
          }

          public void onSuccess(String result) {
            displayMessage(MSG.view_remoteAgentInstall_startAgentResults(result));
            agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't do
                                // it here

            // tell the success handler
            invokeSuccessHandler(Type.START);
          }
        });
  }

  private void stopAgent() {
    disableButtons(true);
    createWaitingWindow(MSG.view_remoteAgentInstall_stopAgentPleaseWait(), true);
    remoteInstallService.stopAgent(
        getRemoteAccessInfo(),
        getAgentInstallPath(),
        new AsyncCallback<String>() {
          public void onFailure(Throwable caught) {
            displayError(MSG.view_remoteAgentInstall_error_6(), caught);
            doneProcessing();
          }

          public void onSuccess(String result) {
            displayMessage(MSG.view_remoteAgentInstall_stopAgentResults(result));
            agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't do
                                // it here

            // tell the success handler
            invokeSuccessHandler(Type.STOP);
          }
        });
  }

  private void buildInstallInfoCanvas(AgentInstallInfo info) {
    DynamicForm infoForm = new DynamicForm();
    infoForm.setMargin(20);
    infoForm.setWidth100();
    infoForm.setHeight100();

    HeaderItem infoHeader = new HeaderItem();
    infoHeader.setValue(MSG.view_remoteAgentInstall_installInfo());

    StaticTextItem version = new StaticTextItem("version", MSG.common_title_version());
    version.setValue(info.getVersion());

    StaticTextItem path = new StaticTextItem("path", MSG.common_title_path());
    path.setValue(info.getPath());

    StaticTextItem owner = new StaticTextItem("owner", MSG.common_title_owner());
    owner.setValue(info.getOwner());

    StaticTextItem config = new StaticTextItem("config", MSG.common_title_configuration());
    config.setValue(info.getConfigurationStartString());

    CanvasItem listCanvas = new CanvasItem();
    listCanvas.setShowTitle(false);
    listCanvas.setColSpan(2);

    VLayout listLayout = new VLayout(0);
    listLayout.setWidth100();
    listLayout.setHeight100();

    ListGrid listGrid =
        new ListGrid() {
          @Override
          protected Canvas getExpansionComponent(ListGridRecord record) {
            Canvas canvas = super.getExpansionComponent(record);
            canvas.setPadding(5);
            return canvas;
          }
        };
    listGrid.setWidth100();
    listGrid.setHeight100();
    listGrid.setCanExpandRecords(true);
    listGrid.setExpansionMode(ExpansionMode.DETAIL_FIELD);
    listGrid.setDetailField("result");
    ListGridField step = new ListGridField("description", MSG.view_remoteAgentInstall_step());
    ListGridField result = new ListGridField("result", MSG.view_remoteAgentInstall_result());
    ListGridField resultCode =
        new ListGridField("resultCode", MSG.view_remoteAgentInstall_resultCode(), 90);
    ListGridField duration = new ListGridField("duration", MSG.common_title_duration(), 90);
    listGrid.setFields(step, result, resultCode, duration);
    listGrid.setData(getStepRecords(info));

    listLayout.addMember(listGrid);
    listCanvas.setCanvas(listLayout);

    // Replace the current info with just the install steps
    for (Canvas canvas : this.getChildren()) {
      canvas.markForDestroy();
    }

    createAgentStatusTextItem();
    infoForm.setFields(infoHeader, version, path, owner, config, agentStatusText, listCanvas);

    addMember(infoForm);

    this.setMembersMargin(1);
    this.markForRedraw();
  }

  private ListGridRecord[] getStepRecords(AgentInstallInfo info) {
    ArrayList<ListGridRecord> steps = new ArrayList<ListGridRecord>();

    for (AgentInstallStep step : info.getSteps()) {
      ListGridRecord rec = new ListGridRecord();
      rec.setAttribute("description", step.getDescription());
      String result = step.getResult();
      if (result == null || result.trim().length() == 0) {
        result = MSG.view_remoteAgentInstall_resultCode() + "=" + step.getResultCode();
      }
      rec.setAttribute("result", result);
      rec.setAttribute("resultCode", "" + step.getResultCode());
      rec.setAttribute(
          "duration",
          MeasurementConverterClient.format(
              (double) step.getDuration(), MeasurementUnits.MILLISECONDS, true));
      steps.add(rec);
    }

    return steps.toArray(new ListGridRecord[steps.size()]);
  }

  private void disableCanvas(Canvas obj, boolean disabled) {
    if (obj.isCreated()) {
      obj.setDisabled(disabled);
    }
  }

  private void disableCanvasItem(CanvasItem obj, boolean disabled) {
    if (obj.isDrawn()) {
      obj.setDisabled(disabled);
    }
  }

  private void disableButtons(boolean disabled) {
    disableCanvas(installButton, disabled);
    disableCanvas(uninstallButton, disabled);
    disableCanvas(startButton, disabled);
    disableCanvas(stopButton, disabled);
    disableCanvas(buttonsForm, disabled);
    disableCanvasItem(statusCheckButton, disabled);
    // we only want to mess with this if we are in "install" mode
    if (showInstallButton) {
      disableCanvasItem(findAgentInstallPathButton, disabled);
    }
  }

  private RemoteAccessInfo getRemoteAccessInfo() {
    String host = connectionForm.getValueAsString("host");
    String port = connectionForm.getValueAsString("port");
    String username = connectionForm.getValueAsString("username");
    String password = connectionForm.getValueAsString("password");

    int portInt;
    try {
      portInt = Integer.parseInt(port);
    } catch (NumberFormatException e) {
      portInt = 22;
    }
    connectionForm.setValue("port", portInt);

    RemoteAccessInfo info = new RemoteAccessInfo(host, portInt, username, password);

    if (this.initialAgentInstall != null) {
      info.setAgentName(this.initialAgentInstall.getAgentName());
    }

    boolean rememberme = Boolean.parseBoolean(connectionForm.getValueAsString("rememberme"));
    info.setRememberMe(rememberme);

    info.setHostAuthorized(hostAuthorized);

    return info;
  }

  private String getAgentInstallPath() {
    return agentInstallPath.getValueAsString();
  }

  private class AbsolutePathValidator extends CustomValidator {
    private boolean performCheck = false;

    public AbsolutePathValidator() {
      setErrorMessage(MSG.view_remoteAgentInstall_error_needAbsPath());
    }

    public void setPerformCheck(boolean b) {
      this.performCheck = b;
    }

    public boolean condition(Object value) {
      return (this.performCheck == false)
          || ((value != null) && (value.toString().startsWith("/")));
    }
  }

  // all our remote SSH work should be wrapped in this callback so we can check the SSH
  // connection first. This provides a way to notify the user if the host key fingerprint
  // is unknown or has changed.
  private abstract class CheckSSHConnectionCallback implements AsyncCallback<Void> {
    protected abstract void doActualWork();

    public void execute() {
      disableButtons(true);
      remoteInstallService.checkSSHConnection(getRemoteAccessInfo(), this);
    }

    @Override
    public void onSuccess(Void result) {
      disableButtons(false);
      doActualWork();
    }

    @Override
    public void onFailure(Throwable caught) {
      disableButtons(false);

      // if this failure was because the SSH connection wanted to ask a security question
      // (one of two things - either the host fingerprint is not known and we should add it
      // or the host fingerprint has changed and we should change it), then ask the question
      // (which jsch has provided us and we put in the SSHSecurityException) and if the user
      // answers "yes" then do the work as we originally were asked to do.
      if (caught instanceof SSHSecurityException) {
        SC.ask(
            caught.getMessage(),
            new BooleanCallback() {
              @Override
              public void execute(Boolean value) {
                if (value != null && value.booleanValue()) {
                  hostAuthorized = true; // the user has just authorized the host
                  doActualWork();
                }
              }
            });
      } else {
        displayError(MSG.view_remoteAgentInstall_error_connError(), caught);
      }
    }
  }

  /**
   * Allows one success handler to be added to this view. When anything is done that is a success,
   * this handler will be called. If you set this to null, any previous success handler will be
   * removed.
   *
   * @param successHandler the handler to call when this view does anything successful.
   */
  public void setSuccessHandler(SuccessHandler successHandler) {
    this.successHandler = successHandler;
  }

  private void invokeSuccessHandler(Type type) {
    if (this.successHandler != null) {
      try {
        this.successHandler.onSuccess(type);
      } catch (Exception e) {
        displayError("success handler failed", e);
      }
    }
  }

  public interface SuccessHandler {
    void onSuccess(Type type);
  }
}
/** @author Greg Hinkle */
public class BundleVersionView extends EnhancedVLayout implements BookmarkableView {

  private BundleGWTServiceAsync bundleManager = GWTServiceLookup.getBundleService();
  private BundleVersion version;
  private boolean canDelete;
  private boolean canDeploy;
  private boolean canTag;

  public BundleVersionView(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
  }

  private void viewBundleVersion(BundleVersion version, ViewId nextViewId) {
    // Whenever a new view request comes in, make sure to clean house to avoid ID conflicts for
    // sub-widgets
    this.destroyMembers();

    this.version = version;

    addMember(
        new BackButton(
            MSG.view_bundle_version_backToBundle() + ": " + version.getBundle().getName(),
            LinkManager.getBundleLink(version.getBundle().getId())));

    addMember(
        new HeaderLabel(
            Canvas.getImgURL("subsystems/bundle/BundleVersion_24.png"),
            version.getName() + ": " + version.getVersion()));

    // conditionally add tags. Defaults to true, not available in JON builds.
    if (CoreGUI.isTagsEnabledForUI()) {
      addMember(createTagEditor());
    }

    addMember(createSummaryForm());

    TabSet tabs = new TabSet();
    tabs.addTab(createRecipeTab());
    tabs.addTab(createLiveDeploymentsTab());
    tabs.addTab(createFilesTab());
    addMember(tabs);

    if (nextViewId != null) {
      if (nextViewId.getPath().equals("recipe")) {
        tabs.selectTab(0);
      } else if (nextViewId.getPath().equals("deployments")) {
        tabs.selectTab(1);
      } else if (nextViewId.getPath().equals("files")) {
        tabs.selectTab(2);
      } else {
        // should we throw an exception? someone gave a bad URL; just bring them to first tab
        tabs.selectTab(0);
      }
    }

    markForRedraw();
  }

  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(4);
    actionItem.setShowTitle(false);
    actionItem.setCanvas(getActionLayout());

    StaticTextItem versionItem = new StaticTextItem("version", MSG.common_title_version());
    versionItem.setValue(version.getVersion());

    StaticTextItem liveDeploymentsItem =
        new StaticTextItem("deployments", MSG.view_bundle_deployments());
    liveDeploymentsItem.setValue(version.getBundleDeployments().size());

    StaticTextItem filesItems = new StaticTextItem("files", MSG.view_bundle_files());
    filesItems.setValue(version.getBundleFiles().size());

    StaticTextItem descriptionItem =
        new StaticTextItem("description", MSG.common_title_description());
    descriptionItem.setValue(version.getDescription());

    form.setFields(versionItem, actionItem, liveDeploymentsItem, filesItems, descriptionItem);
    return form;
  }

  private Canvas getActionLayout() {
    EnhancedVLayout actionLayout = new EnhancedVLayout(10);
    IButton deleteButton = new EnhancedIButton(MSG.common_button_delete(), ButtonColor.RED);
    // deleteButton.setIcon("subsystems/bundle/BundleVersionAction_Delete_16.png");
    deleteButton.addClickHandler(
        new ClickHandler() {
          public void onClick(ClickEvent clickEvent) {
            SC.ask(
                MSG.view_bundle_version_deleteConfirm(),
                new BooleanCallback() {
                  public void execute(Boolean aBoolean) {
                    if (aBoolean) {
                      bundleManager.deleteBundleVersion(
                          version.getId(),
                          false,
                          new AsyncCallback<Void>() {
                            public void onFailure(Throwable caught) {
                              CoreGUI.getErrorHandler()
                                  .handleError(
                                      MSG.view_bundle_version_deleteFailure(version.getVersion()),
                                      caught);
                            }

                            public void onSuccess(Void result) {
                              CoreGUI.getMessageCenter()
                                  .notify(
                                      new Message(
                                          MSG.view_bundle_version_deleteSuccessful(
                                              version.getVersion()),
                                          Message.Severity.Info));
                              // Bundle version is deleted, go back to main bundle view
                              CoreGUI.goToView(
                                  LinkManager.getBundleVersionLink(version.getBundle().getId(), 0),
                                  true);
                            }
                          });
                    }
                  }
                });
          }
        });
    actionLayout.addMember(deleteButton);

    if (!canDelete) {
      deleteButton.setDisabled(true);
    }

    return actionLayout;
  }

  private TagEditorView createTagEditor() {
    boolean readOnly = !this.canTag;
    TagEditorView tagEditor =
        new TagEditorView(
            version.getTags(),
            readOnly,
            new TagsChangedCallback() {
              public void tagsChanged(HashSet<Tag> tags) {
                GWTServiceLookup.getTagService()
                    .updateBundleVersionTags(
                        version.getId(),
                        tags,
                        new AsyncCallback<Void>() {
                          public void onFailure(Throwable caught) {
                            CoreGUI.getErrorHandler()
                                .handleError(
                                    MSG.view_bundle_version_bundleVersionTagUpdateFailure(),
                                    caught);
                          }

                          public void onSuccess(Void result) {
                            CoreGUI.getMessageCenter()
                                .notify(
                                    new Message(
                                        MSG.view_bundle_version_bundleVersionTagUpdateSuccessful(),
                                        Message.Severity.Info));
                          }
                        });
              }
            });
    tagEditor.setAutoHeight();
    tagEditor.setExtraSpace(10);
    return tagEditor;
  }

  private Tab createRecipeTab() {
    Tab tab = new Tab(MSG.view_bundle_recipe());
    DynamicForm form = new DynamicForm();

    TextAreaItem recipeCanvas = new TextAreaItem("recipe", MSG.view_bundle_recipe());
    recipeCanvas.setShowTitle(false);
    recipeCanvas.setColSpan(2);
    recipeCanvas.setWidth("100%");
    recipeCanvas.setHeight("100%");
    recipeCanvas.setValue(version.getRecipe());
    recipeCanvas.addChangeHandler(
        new ChangeHandler() {
          @Override
          public void onChange(ChangeEvent event) {
            // makes this read-only; however, since its not disabled, user can still select/copy the
            // text
            event.cancel();
          }
        });

    form.setHeight100();
    form.setWidth100();
    form.setItems(recipeCanvas);
    tab.setPane(form);
    return tab;
  }

  private Tab createLiveDeploymentsTab() {
    Tab tab = new Tab(MSG.view_bundle_deployments());
    Criteria criteria = new Criteria();
    criteria.setAttribute("bundleVersionId", version.getId());
    tab.setPane(new BundleDeploymentListView(criteria, this.canDeploy));
    return tab;
  }

  private Tab createFilesTab() {
    Tab tab = new Tab(MSG.view_bundle_files());
    FileListView filesView = new FileListView(version.getId());
    tab.setPane(filesView);
    return tab;
  }

  public void renderView(final ViewPath viewPath) {
    int bundleVersionId = Integer.parseInt(viewPath.getCurrent().getPath());

    BundleVersionCriteria criteria = new BundleVersionCriteria();
    criteria.addFilterId(bundleVersionId);
    criteria.fetchBundle(true);
    criteria.fetchBundleFiles(true);
    criteria.fetchBundleDeployments(true);
    criteria.fetchConfigurationDefinition(true);
    criteria.fetchTags(true);

    bundleManager.findBundleVersionsByCriteria(
        criteria,
        new AsyncCallback<PageList<BundleVersion>>() {
          public void onFailure(Throwable caught) {
            CoreGUI.getErrorHandler().handleError(MSG.view_bundle_version_loadFailure(), caught);
          }

          public void onSuccess(PageList<BundleVersion> result) {
            BundleVersion version = result.get(0);
            ViewId nextPath = viewPath.next().getCurrent();
            viewBundleVersion(version, nextPath);
          }
        });
  }
}
/**
 * Shows details of a server plugin.
 *
 * @author John Mazzitelli
 */
public class ServerPluginDetailView extends EnhancedVLayout {

  private final PluginGWTServiceAsync pluginManager = GWTServiceLookup.getPluginService();
  private final int pluginId;

  private final SectionStack sectionStack;
  private SectionStackSection detailsSection = null;
  private SectionStackSection helpSection = null;
  private SectionStackSection controlsSection = null;
  private SectionStackSection pluginConfigSection = null;
  private SectionStackSection scheduledJobsSection = null;
  private int initSectionCount = 0;

  public ServerPluginDetailView(int pluginId) {
    super();
    this.pluginId = pluginId;
    setHeight100();
    setWidth100();
    setOverflow(Overflow.AUTO);

    sectionStack = new SectionStack();
    sectionStack.setVisibilityMode(VisibilityMode.MULTIPLE);
    sectionStack.setWidth100();
    sectionStack.setHeight100();
    sectionStack.setMargin(5);
    sectionStack.setOverflow(Overflow.VISIBLE);
  }

  @Override
  protected void onInit() {
    super.onInit();

    pluginManager.getServerPlugin(
        this.pluginId,
        true,
        new AsyncCallback<ServerPlugin>() {
          public void onSuccess(ServerPlugin plugin) {
            prepareDetailsSection(sectionStack, plugin);
            prepareHelpSection(sectionStack, plugin);
            prepareControlsSection(sectionStack, plugin);
            preparePluginConfigurationSection(sectionStack, plugin);
            prepareScheduledJobsSection(sectionStack, plugin);
          }

          public void onFailure(Throwable caught) {
            CoreGUI.getErrorHandler().handleError(MSG.view_admin_plugins_loadFailure(), caught);
          }
        });
  }

  public boolean isInitialized() {
    return initSectionCount >= 5;
  }

  @Override
  protected void onDraw() {
    super.onDraw();

    // wait until we have all of the sections before we show them. We don't use InitializableView
    // because,
    // it seems they are not supported (in the applicable renderView()) at this level.
    new Timer() {
      final long startTime = System.currentTimeMillis();

      public void run() {
        if (isInitialized()) {
          if (null != detailsSection) {
            sectionStack.addSection(detailsSection);
          }
          if (null != helpSection) {
            sectionStack.addSection(helpSection);
          }
          if (null != controlsSection) {
            sectionStack.addSection(controlsSection);
          }
          if (null != pluginConfigSection) {
            sectionStack.addSection(pluginConfigSection);
          }
          if (null != scheduledJobsSection) {
            sectionStack.addSection(scheduledJobsSection);
          }

          addMember(sectionStack);
          markForRedraw();

        } else {
          // don't wait forever, give up after 20s and show what we have
          long elapsedMillis = System.currentTimeMillis() - startTime;
          if (elapsedMillis > 20000) {
            initSectionCount = 5;
          }
          schedule(100); // Reschedule the timer.
        }
      }
    }.run(); // fire the timer immediately
  }

  private void prepareControlsSection(final SectionStack stack, final ServerPlugin plugin) {
    PluginKey pluginKey = PluginKey.createServerPluginKey(plugin.getType(), plugin.getName());

    pluginManager.getServerPluginControlDefinitions(
        pluginKey,
        new AsyncCallback<ArrayList<ServerPluginControlDefinition>>() {
          public void onSuccess(ArrayList<ServerPluginControlDefinition> result) {
            if (result != null && !result.isEmpty()) {
              SectionStackSection section =
                  new SectionStackSection(MSG.view_admin_plugins_serverControls());
              section.setExpanded(false);
              section.addItem(new ServerPluginControlView(plugin, result));

              controlsSection = section;
            }
            ++initSectionCount;
          }

          public void onFailure(Throwable caught) {
            CoreGUI.getErrorHandler().handleError(MSG.view_admin_plugins_loadFailure(), caught);
          }
        });
  }

  private void preparePluginConfigurationSection(
      final SectionStack stack, final ServerPlugin plugin) {
    final PluginKey pluginKey = PluginKey.createServerPluginKey(plugin.getType(), plugin.getName());

    pluginManager.getServerPluginConfigurationDefinition(
        pluginKey,
        new AsyncCallback<ConfigurationDefinition>() {
          public void onSuccess(ConfigurationDefinition def) {
            if (def != null) {
              EnhancedVLayout layout = new EnhancedVLayout();

              ToolStrip buttons = new ToolStrip();
              buttons.setWidth100();
              buttons.setExtraSpace(10);
              buttons.setMembersMargin(5);
              buttons.setLayoutMargin(5);

              final IButton saveButtonPC = new EnhancedIButton(MSG.common_button_save());

              final IButton resetButtonPC = new EnhancedIButton(MSG.common_button_reset());

              Configuration config = plugin.getPluginConfiguration();
              final ConfigurationEditor editorPC = new ConfigurationEditor(def, config);
              editorPC.setOverflow(Overflow.AUTO);
              editorPC.addPropertyValueChangeListener(
                  new PropertyValueChangeListener() {
                    public void propertyValueChanged(PropertyValueChangeEvent event) {
                      if (event.isInvalidPropertySetChanged()) {
                        Map<String, String> invalidPropertyNames = event.getInvalidPropertyNames();
                        if (invalidPropertyNames.isEmpty()) {
                          saveButtonPC.enable();
                        } else {
                          saveButtonPC.disable();
                        }
                      }
                    }
                  });

              resetButtonPC.addClickHandler(
                  new ClickHandler() {
                    public void onClick(ClickEvent event) {
                      editorPC.reset();
                    }
                  });

              saveButtonPC.addClickHandler(
                  new ClickHandler() {
                    public void onClick(ClickEvent event) {
                      if (!editorPC.validate()) {
                        Message msg =
                            new Message(
                                MSG.view_admin_plugins_serverConfig_badSettings(),
                                Severity.Warning,
                                EnumSet.of(Message.Option.Transient));
                        CoreGUI.getMessageCenter().notify(msg);
                        return;
                      }
                      pluginManager.updateServerPluginConfiguration(
                          pluginKey,
                          editorPC.getConfiguration(),
                          new AsyncCallback<Void>() {
                            public void onSuccess(Void result) {
                              Message m =
                                  new Message(MSG.view_admin_plugins_serverConfig_settingsSaved());
                              CoreGUI.getMessageCenter().notify(m);
                            }

                            public void onFailure(Throwable caught) {
                              CoreGUI.getErrorHandler()
                                  .handleError(
                                      MSG.view_admin_plugins_serverConfig_saveFailed(), caught);
                            }
                          });
                    }
                  });

              buttons.addMember(saveButtonPC);
              buttons.addMember(resetButtonPC);
              layout.addMember(buttons);
              layout.addMember(editorPC);

              SectionStackSection section =
                  new SectionStackSection(MSG.view_admin_plugins_serverConfig());
              section.setExpanded(false);
              section.setItems(layout);

              pluginConfigSection = section;
            }

            ++initSectionCount;
          }

          @Override
          public void onFailure(Throwable caught) {
            CoreGUI.getErrorHandler().handleError(MSG.view_admin_plugins_loadFailure(), caught);
          }
        });
    return;
  }

  private void prepareScheduledJobsSection(final SectionStack stack, final ServerPlugin plugin) {
    final PluginKey pluginKey = PluginKey.createServerPluginKey(plugin.getType(), plugin.getName());

    pluginManager.getServerPluginScheduledJobsDefinition(
        pluginKey,
        new AsyncCallback<ConfigurationDefinition>() {
          public void onSuccess(ConfigurationDefinition def) {
            if (def != null) {
              EnhancedVLayout layout = new EnhancedVLayout();

              ToolStrip buttons = new ToolStrip();
              buttons.setWidth100();
              buttons.setExtraSpace(10);
              buttons.setMembersMargin(5);
              buttons.setLayoutMargin(5);

              final IButton saveButtonSJ = new EnhancedIButton(MSG.common_button_save());
              buttons.addMember(saveButtonSJ);

              final IButton resetButtonSJ = new EnhancedIButton(MSG.common_button_reset());
              buttons.addMember(resetButtonSJ);

              Configuration config = plugin.getScheduledJobsConfiguration();
              final ConfigurationEditor editorSJ = new ConfigurationEditor(def, config);
              editorSJ.setOverflow(Overflow.AUTO);
              editorSJ.addPropertyValueChangeListener(
                  new PropertyValueChangeListener() {
                    public void propertyValueChanged(PropertyValueChangeEvent event) {
                      if (event.isInvalidPropertySetChanged()) {
                        Map<String, String> invalidPropertyNames = event.getInvalidPropertyNames();
                        if (invalidPropertyNames.isEmpty()) {
                          saveButtonSJ.enable();
                        } else {
                          saveButtonSJ.disable();
                        }
                      }
                    }
                  });

              resetButtonSJ.addClickHandler(
                  new ClickHandler() {
                    public void onClick(ClickEvent event) {
                      editorSJ.reset();
                    }
                  });

              saveButtonSJ.addClickHandler(
                  new ClickHandler() {
                    public void onClick(ClickEvent event) {
                      if (!editorSJ.validate()) {
                        Message msg =
                            new Message(
                                MSG.view_admin_plugins_serverConfig_badSettings(),
                                Severity.Warning,
                                EnumSet.of(Message.Option.Transient));
                        CoreGUI.getMessageCenter().notify(msg);
                        return;
                      }
                      pluginManager.updateServerPluginScheduledJobs(
                          pluginKey,
                          editorSJ.getConfiguration(),
                          new AsyncCallback<Void>() {
                            public void onSuccess(Void result) {
                              Message m =
                                  new Message(MSG.view_admin_plugins_serverConfig_settingsSaved());
                              CoreGUI.getMessageCenter().notify(m);
                            }

                            public void onFailure(Throwable caught) {
                              CoreGUI.getErrorHandler()
                                  .handleError(
                                      MSG.view_admin_plugins_serverConfig_saveFailed(), caught);
                            }
                          });
                    }
                  });

              layout.addMember(buttons);
              layout.addMember(editorSJ);

              SectionStackSection section =
                  new SectionStackSection(MSG.view_admin_plugins_serverScheduleJobs());
              section.setExpanded(false);
              section.setItems(layout);

              scheduledJobsSection = section;
            }

            ++initSectionCount;
          }

          @Override
          public void onFailure(Throwable caught) {
            CoreGUI.getErrorHandler().handleError(MSG.view_admin_plugins_loadFailure(), caught);
          }
        });
    return;
  }

  private void prepareHelpSection(SectionStack stack, ServerPlugin plugin) {
    if (plugin.getHelp() != null && plugin.getHelp().length() > 0) {
      SectionStackSection section = new SectionStackSection(MSG.common_title_help());
      section.setExpanded(true);
      Label help = new Label(plugin.getHelp());
      section.setItems(help);

      helpSection = section;
    }

    ++initSectionCount;
    return;
  }

  private void prepareDetailsSection(SectionStack stack, ServerPlugin plugin) {
    DynamicForm form = new DynamicForm();
    form.setMargin(10);
    form.setWidth100();
    form.setWrapItemTitles(false);
    form.setNumCols(4);

    StaticTextItem nameItem = new StaticTextItem("name", MSG.common_title_name());
    nameItem.setValue(plugin.getName());

    StaticTextItem displayNameItem =
        new StaticTextItem("displayName", MSG.common_title_display_name());
    displayNameItem.setValue(plugin.getDisplayName());

    StaticTextItem versionItem = new StaticTextItem("version", MSG.common_title_version());
    versionItem.setValue(plugin.getVersion());

    StaticTextItem md5Item = new StaticTextItem("MD5", "MD5");
    md5Item.setValue(plugin.getMD5());

    StaticTextItem pathItem = new StaticTextItem("path", MSG.common_title_path());
    pathItem.setValue(plugin.getPath());

    StaticTextItem ampsItem =
        new StaticTextItem("ampsVersion", "AMPS " + MSG.common_title_version());
    ampsItem.setValue(plugin.getAmpsVersion());

    StaticTextItem descItem = new StaticTextItem("desc", MSG.common_title_description());
    descItem.setValue(plugin.getDescription());

    StaticTextItem mtimeItem = new StaticTextItem("mtime", MSG.common_title_lastUpdated());
    mtimeItem.setValue(
        TimestampCellFormatter.format(
            Long.valueOf(plugin.getMtime()), TimestampCellFormatter.DATE_TIME_FORMAT_MEDIUM));

    StaticTextItem kindItem = new StaticTextItem("kind", MSG.common_title_kind());
    switch (plugin.getDeployment()) {
      case AGENT:
        kindItem.setValue(MSG.view_admin_plugins_agent());
        break;
      case SERVER:
        kindItem.setValue(MSG.view_admin_plugins_server());
        break;
    }

    CanvasItem enabledItem = new CanvasItem("enabled", MSG.common_title_enabled());
    Img img = new Img(ImageManager.getAvailabilityIcon(plugin.isEnabled()), 16, 16);
    enabledItem.setCanvas(img);

    StaticTextItem typeItem = new StaticTextItem("type", MSG.common_title_type());
    typeItem.setValue(plugin.getType());

    form.setItems(
        displayNameItem,
        nameItem,
        versionItem,
        ampsItem,
        md5Item,
        kindItem,
        descItem,
        pathItem,
        mtimeItem,
        enabledItem,
        typeItem);

    SectionStackSection section = new SectionStackSection(MSG.common_title_details());
    section.setExpanded(true);
    section.setItems(form);

    detailsSection = section;
    ++initSectionCount;

    return;
  }
}
/** @author Greg Hinkle */
public class PluginTypeTreeView extends EnhancedVLayout {

  private ResourceTypeGWTServiceAsync resourceTypeService =
      GWTServiceLookup.getResourceTypeGWTService();
  private final boolean showIgnoredResourceTypes;

  public PluginTypeTreeView(boolean showIgnoredResourceTypes) {
    super();
    this.showIgnoredResourceTypes = showIgnoredResourceTypes;
    setWidth100();
    setHeight100();
  }

  @Override
  protected void onDraw() {
    super.onDraw();

    final TreeGrid treeGrid = new CustomResourceTypeTreeGrid();

    treeGrid.setHeight100();

    treeGrid.setTitle(MSG.view_type_resourceTypes());
    treeGrid.setAnimateFolders(false);
    treeGrid.setResizeFieldsInRealTime(true);

    final TreeGridField name, plugin, category;
    name = new TreeGridField("name");
    plugin = new TreeGridField("plugin");
    category = new TreeGridField("category");

    treeGrid.setFields(name, plugin, category);

    addMember(treeGrid);

    ResourceTypeCriteria criteria = new ResourceTypeCriteria();
    criteria.addFilterIgnored((showIgnoredResourceTypes ? (Boolean) null : Boolean.FALSE));
    criteria.fetchParentResourceTypes(true);
    criteria.setPageControl(PageControl.getUnlimitedInstance());

    resourceTypeService.findResourceTypesByCriteria(
        criteria,
        new AsyncCallback<PageList<ResourceType>>() {
          public void onFailure(Throwable caught) {
            CoreGUI.getErrorHandler().handleError(MSG.widget_typeTree_loadFail(), caught);
          }

          public void onSuccess(PageList<ResourceType> result) {

            treeGrid.getTree().linkNodes(ResourceTypePluginTreeDataSource.buildNodes(result));
          }
        });
  }

  public static class CustomResourceTypeTreeGrid extends TreeGrid {
    @Override
    protected String getIcon(Record record, boolean defaultState) {

      if (record instanceof TreeNode) {
        // boolean open = getTree().isOpen((TreeNode) record);

        if (record instanceof ResourceTypePluginTreeDataSource.ResourceTypeTreeNode) {
          ResourceType resourceType =
              ((ResourceTypePluginTreeDataSource.ResourceTypeTreeNode) record).getResourceType();

          return ImageManager.getResourceIcon(resourceType.getCategory());
        } else if (record instanceof ResourceTypePluginTreeDataSource.PluginTreeNode) {
          return "types/plugin_16.png";
        }
      }
      return null;
    }
  }
}