/**
 * A panel that allows to edit and plot from a set of query groups.
 *
 * @author Daniel Moraru
 */
public final class DashboardSelectorPanel extends ArtefactSelectorPanel<DashboardInfo> {
  private static final long serialVersionUID = 1751373651781903520L;

  /** Logger */
  private static final AppLogger logger = AppLoggerFactory.getLogger(DashboardSelectorPanel.class);

  /** Callback */
  private Callback callback;
  /** DashboardRepositoryService */
  private DashboardRepositoryService fDashboardRepository;
  /** Tree explorer */
  private SessionTreeExplorer fTreeExplorer;
  /** Event handler */
  private EventHandler fEventHandlef;
  /** Artefact info locator */
  private SessionArtefactInfoLocator fArtefactInfoLocator;

  /** Callback. */
  public interface Callback {
    /**
     * Invoked when a request to plot a dashboard was made.
     *
     * @param di the dashboard
     */
    void plot(DashboardId did);
  }

  /** Event handler. */
  private final class EventHandler implements DashboardEditorDialog.Listener {
    /**
     * @see
     *     com.ixora.rms.ui.artefacts.dashboard.DashboardEditorDialog.Listener#savedDashboard(ResourceId,
     *     com.ixora.rms.repository.QueryGroup)
     */
    public void savedDashboard(ResourceId context, Dashboard group) {
      handleSavedDashboard(context, group);
    }
  }

  /**
   * Constructor used by a log replay session.
   *
   * @param viewContainer
   * @param dashboardRepository
   * @param viewRepository
   * @param sessionData
   * @param treeExplorer
   * @param cb
   */
  public DashboardSelectorPanel(
      RMSViewContainer viewContainer,
      DashboardRepositoryService dashboardRepository,
      DataViewRepositoryService viewRepository,
      SessionModel sessionData,
      SessionTreeExplorer treeExplorer,
      Callback cb) {
    this(
        viewContainer,
        dashboardRepository,
        viewRepository,
        sessionData,
        null,
        treeExplorer,
        cb,
        true);
  }

  /**
   * Constructor used by a live session.
   *
   * @param viewContainer
   * @param dashboardRepository
   * @param viewRepository
   * @param sessionData
   * @param queryRealizer
   * @param treeExplorer
   * @param cb
   * @param b
   */
  public DashboardSelectorPanel(
      RMSViewContainer viewContainer,
      DashboardRepositoryService dashboardRepository,
      DataViewRepositoryService viewRepository,
      SessionModel sessionData,
      QueryRealizer queryRealizer,
      SessionTreeExplorer treeExplorer,
      Callback cb) {
    this(
        viewContainer,
        dashboardRepository,
        viewRepository,
        sessionData,
        queryRealizer,
        treeExplorer,
        cb,
        false);
  }

  /**
   * Constructor.
   *
   * @param viewContainer
   * @param dashboardRepository
   * @param viewRepository
   * @param sessionData
   * @param queryRealizer
   * @param treeExplorer
   * @param cb
   * @param logReplayMode
   */
  private DashboardSelectorPanel(
      RMSViewContainer viewContainer,
      DashboardRepositoryService dashboardRepository,
      DataViewRepositoryService viewRepository,
      SessionModel sessionData,
      QueryRealizer queryRealizer,
      SessionTreeExplorer treeExplorer,
      Callback cb,
      boolean logReplayMode) {
    super(
        viewContainer,
        sessionData,
        queryRealizer,
        new DashboardTableModel(viewContainer, sessionData, logReplayMode),
        Msg.ACTIONS_ADD_DASHBOARD,
        Msg.ACTIONS_REMOVE_DASHBOARD,
        Msg.ACTIONS_EDIT_DASHBOARD,
        Msg.ACTIONS_PLOT_DASHBOARD);
    this.fTreeExplorer = treeExplorer;
    this.callback = cb;
    this.fDashboardRepository = dashboardRepository;
    this.fArtefactInfoLocator = new SessionArtefactInfoLocatorImpl(sessionData, viewRepository);
    this.fEventHandlef = new EventHandler();
  }

  /**
   * @param context
   * @param db
   */
  public void setDashboards(ResourceId context, Collection<DashboardInfo> db) {
    this.setArtefacts(context, db);
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#refreshArtefactStatus() */
  protected void refreshArtefactStatus() {
    this.fSessionData.getDashboardHelper().recalculateDashboardsStatus(fContext);
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#uncommittedArtifacts() */
  protected boolean uncommittedArtifacts() {
    ArtefactInfoContainer aic = this.fSessionData.getArtefactContainerForResource(fContext, true);
    if (aic == null) {
      logger.error("Couldn't find info container for: " + fContext);
      return false;
    }
    return aic.uncommittedVisibleDashboards();
  }

  /** Cancels changes. */
  protected void handleCancel() {
    try {
      fSessionData.getDashboardHelper().rollbackDashboards(this.fContext);
      getDashboardTableModel().fireTableDataChanged();
      this.fActionApply.setEnabled(false);
      this.fActionCancel.setEnabled(false);
    } catch (Exception e) {
      UIExceptionMgr.userException(e);
    }
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#handleApplyChanges() */
  protected void handleApplyChanges() {
    try {
      applyChangesLocally();
    } catch (Exception e) {
      handleCancel();
      UIExceptionMgr.userException(e);
    }
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#handlePlotArtefact() */
  protected void handlePlotArtefact() {
    try {
      final JTable table = getJTableArtefacts();
      final int[] sel = table.getSelectedRows();
      if (Utils.isEmptyArray(sel)) {
        return;
      }

      this.fViewContainer
          .getAppWorker()
          .runJobSynch(
              new UIWorkerJobDefault(
                  fViewContainer.getAppFrame(),
                  Cursor.WAIT_CURSOR,
                  MessageRepository.get(Msg.TEXT_PLOTTING_DASHBOARD)) {
                public void work() throws Exception {
                  for (int idx : sel) {
                    DashboardInfo di = (DashboardInfo) table.getModel().getValueAt(idx, 1);

                    Dashboard dtls = di.getDashboard();
                    if (dtls == null) {
                      logger.error("No dashboard");
                      return;
                    }

                    DataViewId[] members = dtls.getViews();
                    ResourceId[] counters = dtls.getCounters();
                    if (Utils.isEmptyArray(members) && Utils.isEmptyArray(counters)) {
                      // TODO localize
                      throw new RMSException(
                          "Dashboard " + di.getTranslatedName() + " has no data views.");
                    }

                    if (!di.getFlag(DataViewInfo.ENABLED) && di.isCommitted()) {
                      // enable it first
                      ((DashboardTableModel) fTableModelArtefacts).enableDashboard(idx);
                      applyChangesLocally();
                    }

                    callback.plot(new DashboardId(fContext, dtls.getName()));
                  }
                }

                public void finished(Throwable ex) {
                  ; // nothing, synched job
                }
              });
    } catch (Exception ex) {
      UIExceptionMgr.userException(ex);
    }
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#handleEditArtefact() */
  protected void handleEditArtefact() {
    try {
      JTable table = getJTableArtefacts();
      int sel = table.getSelectedRow();
      if (sel < 0) {
        return;
      }
      DashboardInfo cd = (DashboardInfo) table.getModel().getValueAt(sel, 1);
      DashboardEditorDialog editor =
          new DashboardEditorDialog(
              fViewContainer, fTreeExplorer, fDashboardRepository, fEventHandlef);
      editor.setModal(true);
      editor.edit(fSessionData, fContext, fAllSUOVersions, cd.getDashboard());
      UIUtils.centerDialogAndShow(fViewContainer.getAppFrame(), editor);
    } catch (Exception ex) {
      UIExceptionMgr.userException(ex);
    }
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#getXMLDefinitionForSelectedArtefact() */
  protected String getXMLDefinitionForSelectedArtefact() throws Exception {
    JTable table = getJTableArtefacts();
    int sel = table.getSelectedRow();
    if (sel < 0) {
      return "";
    }
    DashboardInfo dashboard = (DashboardInfo) getArtefactInfoAtRow(sel);
    return XMLUtils.toXMLBuffer(null, dashboard.getDashboard(), "rms", false).toString();
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#handleAddArtefact() */
  protected void handleAddArtefact() {
    try {
      DashboardEditorDialog editor =
          new DashboardEditorDialog(
              fViewContainer, fTreeExplorer, fDashboardRepository, fEventHandlef);
      editor.setModal(true);
      editor.edit(fSessionData, fContext, fAllSUOVersions, null);
      UIUtils.centerDialogAndShow(fViewContainer.getAppFrame(), editor);
    } catch (Exception ex) {
      UIExceptionMgr.userException(ex);
    }
  }

  /** @see com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#handleRemoveArtefact() */
  protected void handleRemoveArtefact() {
    try {
      JTable table = getJTableArtefacts();
      int[] sel = table.getSelectedRows();
      if (Utils.isEmptyArray(sel)) {
        return;
      }
      for (int idx : sel) {
        DashboardInfo gi = (DashboardInfo) table.getModel().getValueAt(idx, 1);
        DashboardMap map = fDashboardRepository.getDashboardMap(fContext);
        if (map == null) {
          logger.error("Couldn't find query gruop map for context: " + this.fContext);
          return;
        }
        // ask for confitmation
        if (!UIUtils.getBooleanOkCancelInput(
            this.fViewContainer.getAppFrame(),
            MessageRepository.get(Msg.TITLE_CONFIRM_REMOVE_DASHBOARD),
            MessageRepository.get(
                Msg.TEXT_CONFIRM_REMOVE_DASHBOARD, new String[] {gi.getTranslatedName()}))) {
          return;
        }
        // remove the dashboard only for the current fSUOVersion
        map.remove(gi.getDashboard().getName(), fSUOVersion);
        fDashboardRepository.setDashboardMap(fContext, map);
        fDashboardRepository.save();
        // update model
        fSessionData.getDashboardHelper().removeDashboard(fContext, gi.getDashboard().getName());
        // refresh table model
        refreshTableModel();
      }
    } catch (Exception ex) {
      UIExceptionMgr.userException(ex);
    }
  }

  /**
   * @see
   *     com.ixora.rms.ui.artefacts.ArtefactSelectorPanel#showPlotMenuItemForArtefact(com.ixora.rms.client.model.ArtefactInfo)
   */
  protected boolean showPlotMenuItemForArtefact(ArtefactInfo ai) {
    // show the plot menu no matter what is the state of the artefact
    return ai.isCommitted();
  }

  /** Updates the query group table model. */
  private void refreshTableModel() {
    setDescriptionText(null);
    // reread data from model
    ArtefactInfoContainer aic = fSessionData.getArtefactContainerForResource(fContext, true);
    if (aic == null) {
      logger.error("Couldn't find dashboard info container for: " + fContext);
      getDashboardTableModel().setArtefacts(fContext, null);
    } else {
      getDashboardTableModel().setArtefacts(fContext, aic.getDashboardInfo());
    }
  }

  /** @return DashboardTableModel */
  private DashboardTableModel getDashboardTableModel() {
    return (DashboardTableModel) getJTableArtefacts().getModel();
  }

  /**
   * @param context
   * @param dashboard
   */
  private void handleSavedDashboard(ResourceId context, Dashboard dashboard) {
    // add to model only if the data view applies for the given context
    String version = fSessionData.getAgentVersionInContext(context);
    // add to model only if:
    // 1. outside of an agent context
    // 2. dashboard applies to version in context
    if (version == null || dashboard.appliesToAgentVersion(version)) {
      fSessionData.getDashboardHelper().addDashboard(context, dashboard);
    } else {
      // otherwise remove
      fSessionData.getDashboardHelper().removeDashboard(context, dashboard.getName());
    }
    // refresh table model
    refreshTableModel();
  }

  /**
   * Applies changes at global level i.e it will realize all realizable query groups in the session
   * model.
   */
  /*    private void applyChangesGlobally() {
  		// get all queries to realize
  	    Map map = sessionData.getQueryGroupHelper().getAllDashboardsToRealize();
  	    ResourceId rid;
  	    Collection groups;
  	    Map.Entry me;
  	    for(Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
              me = (Map.Entry)iter.next();
              rid = (ResourceId)me.getKey();
              groups = (Collection)me.getValue();
              if(groups != null) {
  				DashboardInfo ginfo;
  				for(Iterator iter1 = groups.iterator(); iter1.hasNext();) {
  					 ginfo = (DashboardInfo)iter1.next();
  					 // get queries
  					 QueryId[] members = ginfo.getDashboard().getMembers();
  					 for(int i = 0; i < members.length; i++) {
  					    QueryId m = members[i];
  	                    if(context != null) {
  	                        m = m.complete(context);
  	                    }
  	                    if(context != null) {
  	                        m = m.complete(context);
  	                    }
  	                    ArtefactInfoContainer aic = sessionData.getArtefactContainerForResource(m.getContext());
  	                    if(aic == null) {
  	                        logger.error("Couldn't find info container for: " + m.getContext());
  	                        break;
  	                    }
  	                    final QueryInfo qinfo = aic.getQueryInfo(m.getName());
  	                    if(qinfo == null) {
  	                        logger.error("Couldn't find query info for: " + m);
  	                        break;
  	                    }
  	                    final QueryId fm = m;
  	                    // Note: this method is reading from the session model
  						// and as a result it can only be used safely from
  						// the event dispatching thread
  						this.viewContainer.runJobSynch(new UIWorkerJobDefault(
  								viewContainer,
  								Cursor.WAIT_CURSOR,
  								MessageRepository.get(
  									Msg.TEXT_REALIZINGQUERY,
  									new String[]{qinfo.getTranslatedName()})) {
  							public void work() throws Exception {
  								queryRealizer.realizeQuery(
  									fm.getContext(), qinfo.getQuery());					}
  							public void finished(Throwable ex) {
  								if(ex != null) {
  									UIExceptionMgr.userException(ex);
  								}
  							}
  						});
  					}
  				}
              }
  	    }

  		// get all query groups to unrealize
  	    map = sessionData.getQueryGroupHelper().getAllDashboardsToUnRealize();
  	    for(Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
              me = (Map.Entry)iter.next();
              rid = (ResourceId)me.getKey();
              groups = (Collection)me.getValue();
              if(groups != null) {
                  DashboardInfo ginfo;
  				for(Iterator iter1 = groups.iterator(); iter1.hasNext();) {
  					 ginfo = (DashboardInfo)iter1.next();
  					 // get queries
  					 QueryId[] members = ginfo.getDashboard().getMembers();
  					 for(int i = 0; i < members.length; i++) {
  					    QueryId m = members[i];
  	                    if(context != null) {
  	                        m = m.complete(context);
  	                    }
  	                    if(context != null) {
  	                        m = m.complete(context);
  	                    }
  	                    ArtefactInfoContainer aic = sessionData.getArtefactContainerForResource(m.getContext());
  	                    if(aic == null) {
  	                        logger.error("Couldn't find query container for: " + m.getContext());
  	                        break;
  	                    }
  	                    final QueryInfo qinfo = aic.getQueryInfo(m.getName());
  	                    if(qinfo == null) {
  	                        logger.error("Couldn't find query info for: " + m);
  	                        break;
  	                    }
  	                    final QueryId fm = m;
  	                    // Note: this method is reading from the session model
  						// and as a result it can only be used safely from
  						// the event dispatching thread
  						this.viewContainer.runJobSynch(new UIWorkerJobDefault(
  								viewContainer,
  								Cursor.WAIT_CURSOR,
  								MessageRepository.get(
  									Msg.TEXT_REALIZINGQUERY,
  									new String[]{qinfo.getTranslatedName()})) {
  							public void work() throws Exception {
  								queryRealizer.unrealizeQuery(
  									fm.getContext(), qinfo.getQuery());					}
  							public void finished(Throwable ex) {
  								if(ex != null) {
  									UIExceptionMgr.userException(ex);
  								}
  							}
  						});
  					 }
  				}
              }
          }

          sessionData.getQueryGroupHelper().recalculateDashboardsStatus(context);
  		getQueryGroupTableModel().fireTableDataChanged();
  		actionApply.setEnabled(false);
  		actionCancel.setEnabled(false);
      }
  */

  /** Applies only changes made to the current context. */
  private void applyChangesLocally() {
    // get all dashboards  to realize
    Collection<DashboardInfo> dashboards = getDashboardTableModel().getDashboardsToRealize();
    if (dashboards != null) {
      for (DashboardInfo dinfo : dashboards) {
        // register views with the query realizer
        DataViewId[] views = dinfo.getDashboard().getViews();
        if (!Utils.isEmptyArray(views)) {
          for (DataViewId view : views) {
            if (fContext != null) {
              view = view.complete(fContext);
            }
            // ask the locator for info on the required data view
            final SessionDataViewInfo dvInfo = this.fArtefactInfoLocator.getDataViewInfo(view);
            if (dvInfo == null) {
              if (logger.isTraceEnabled()) {
                logger.error("Couldn't find data view info for: " + view + ". Skipping...");
              }
              continue;
            }
            final DataViewId fv = view;
            // Note: this method is reading from the session model
            // and as a result it can only be used safely from
            // the event dispatching thread
            this.fViewContainer
                .getAppWorker()
                .runJobSynch(
                    new UIWorkerJobDefault(
                        fViewContainer.getAppFrame(),
                        Cursor.WAIT_CURSOR,
                        MessageRepository.get(
                            Msg.TEXT_REALIZING_DATAVIEW,
                            new String[] {dvInfo.getTranslatedName()})) {
                      public void work() throws Exception {
                        fQueryRealizer.realizeQuery(
                            fv.getContext(),
                            dvInfo.getDataView().getQueryDef(),
                            new QueryRealizer.Callback() {
                              public boolean acceptIncreaseInMonitoringLevel(
                                  List<ResourceInfo> counters) {
                                boolean ret =
                                    UIUtils.getBooleanYesNoInput(
                                        fViewContainer.getAppFrame(),
                                        MessageRepository.get(
                                            Msg.TITLE_CONFIRM_MONITORING_LEVEL_INCREASE),
                                        MessageRepository.get(
                                            Msg
                                                .TEXT_CONFIRM_MONITORING_LEVEL_INCREASE_FOR_DATA_VIEW,
                                            new String[] {dvInfo.getTranslatedName()}));
                                if (!ret) {
                                  // undo changes
                                  fSessionData
                                      .getDataViewHelper()
                                      .rollbackDataView(fv.getContext(), fv.getName());
                                }
                                return ret;
                              }
                            });
                      }

                      public void finished(Throwable ex) {}
                    });
          }
        }
        // register counters with the query realizer
        // for every counter create a query and register it
        ResourceId[] counters = dinfo.getDashboard().getCounters();
        if (!Utils.isEmptyArray(counters)) {
          for (ResourceId counter : counters) {
            if (fContext != null) {
              counter = counter.complete(fContext);
            }
            final SingleCounterQueryDef query = new SingleCounterQueryDef(counter, null, null);
            final ResourceId counterContext = counter.getSubResourceId(ResourceId.ENTITY);

            // add query to the model
            fSessionData.getQueryHelper().addQuery(counterContext, query);

            String translatedCounterName = counter.getCounterId().toString();
            // ask the locator for info on this counter
            SessionResourceInfo rInfo = this.fArtefactInfoLocator.getResourceInfo(counter);
            if (rInfo != null && rInfo.getCounterInfo() != null) {
              translatedCounterName = rInfo.getCounterInfo().getTranslatedName();
            }
            final String finalTranslatedCounterName = translatedCounterName;
            final ResourceId fc = counter;
            // Note: this method is reading from the session model
            // and as a result it can only be used safely from
            // the event dispatching thread
            this.fViewContainer
                .getAppWorker()
                .runJobSynch(
                    new UIWorkerJobDefault(
                        fViewContainer.getAppFrame(),
                        Cursor.WAIT_CURSOR,
                        MessageRepository.get(
                            Msg.TEXT_REALIZING_DATAVIEW, new String[] {translatedCounterName})) {
                      public void work() throws Exception {
                        fQueryRealizer.realizeQuery(
                            counterContext,
                            query,
                            new QueryRealizer.Callback() {
                              public boolean acceptIncreaseInMonitoringLevel(
                                  List<ResourceInfo> counters) {
                                boolean ret =
                                    UIUtils.getBooleanYesNoInput(
                                        fViewContainer.getAppFrame(),
                                        MessageRepository.get(
                                            Msg.TITLE_CONFIRM_MONITORING_LEVEL_INCREASE),
                                        MessageRepository.get(
                                            Msg.TEXT_CONFIRM_MONITORING_LEVEL_INCREASE_FOR_COUNTER,
                                            new String[] {finalTranslatedCounterName}));
                                if (!ret) {
                                  // undo changes
                                  fSessionData.getCounterHelper().rollbackCounter(fc, true);
                                }
                                return ret;
                              }
                            });
                      }

                      public void finished(Throwable ex) {
                        if (ex != null) {
                          UIExceptionMgr.userException(ex);
                        }
                      }
                    });
          }
        }
      }
    }

    // get all dashboards to unrealize
    dashboards = getDashboardTableModel().getDashboardsToUnRealize();
    if (dashboards != null) {
      for (DashboardInfo dinfo : dashboards) {
        // unregister views with the query realizer
        DataViewId[] views = dinfo.getDashboard().getViews();
        // get views
        if (!Utils.isEmptyArray(views)) {
          for (DataViewId view : views) {
            if (fContext != null) {
              view = view.complete(fContext);
            }
            // ask the locator for info on the required data view
            String viewTranslatedName = view.getName();
            final SessionDataViewInfo dvInfo = this.fArtefactInfoLocator.getDataViewInfo(view);
            if (dvInfo == null) {
              if (logger.isTraceEnabled()) {
                logger.error("Couldn't find data view info for: " + view);
              }
            } else {
              viewTranslatedName = dvInfo.getTranslatedName();
            }
            final DataViewId fv = view;
            // Note: this method is reading from the session model
            // and as a result it can only be used safely from
            // the event dispatching thread
            this.fViewContainer
                .getAppWorker()
                .runJobSynch(
                    new UIWorkerJobDefault(
                        fViewContainer.getAppFrame(),
                        Cursor.WAIT_CURSOR,
                        MessageRepository.get(
                            Msg.TEXT_REALIZING_DATAVIEW, new String[] {viewTranslatedName})) {
                      public void work() throws Exception {
                        QueryId qid = new QueryId(fv.getContext(), fv.getName());
                        fQueryRealizer.unrealizeQuery(qid, false);
                      }

                      public void finished(Throwable ex) {
                        if (ex != null) {
                          UIExceptionMgr.userException(ex);
                        }
                      }
                    });
          }

          // unregister counters with the query realizer
          ResourceId[] counters = dinfo.getDashboard().getCounters();
          if (!Utils.isEmptyArray(counters)) {
            for (ResourceId counter : counters) {
              if (fContext != null) {
                counter = counter.complete(fContext);
              }
              final ResourceId counterContext = counter.getSubResourceId(ResourceId.ENTITY);
              String translatedCounterName = counter.getCounterId().toString();
              // ask the locator for info on this counter
              SessionResourceInfo rInfo = this.fArtefactInfoLocator.getResourceInfo(counter);
              if (rInfo != null && rInfo.getCounterInfo() != null) {
                translatedCounterName = rInfo.getCounterInfo().getTranslatedName();
              }
              final ResourceId finalCounter = counter;
              // Note: this method is reading from the session model
              // and as a result it can only be used safely from
              // the event dispatching thread
              this.fViewContainer
                  .getAppWorker()
                  .runJobSynch(
                      new UIWorkerJobDefault(
                          fViewContainer.getAppFrame(),
                          Cursor.WAIT_CURSOR,
                          MessageRepository.get(
                              Msg.TEXT_REALIZING_DATAVIEW, new String[] {translatedCounterName})) {
                        public void work() throws Exception {
                          QueryId queryId =
                              new QueryId(counterContext, finalCounter.getCounterId().toString());
                          fQueryRealizer.unrealizeQuery(queryId, false);
                        }

                        public void finished(Throwable ex) {
                          if (ex != null) {
                            UIExceptionMgr.userException(ex);
                          }
                        }
                      });
            }
          }

          String dashboardName = dinfo.getDashboard().getName();
          fSessionData
              .getDashboardHelper()
              .setDashboardFlag(ArtefactInfo.ENABLED, fContext, dashboardName, false, true);
        }
      }
    }
    fSessionData.getDashboardHelper().recalculateDashboardsStatus(fContext);
    getDashboardTableModel().fireTableDataChanged();
    fActionApply.setEnabled(false);
    fActionCancel.setEnabled(false);
  }
}
Example #2
0
/** SQLBasedEntity */
public class SQLBasedEntity extends RootEntity {
  private static final long serialVersionUID = -9071259766670714662L;
  /** Logger */
  private static final AppLogger logger = AppLoggerFactory.getLogger(SQLBasedEntity.class);
  /** List of database connections */
  private List<Connection> connections = new LinkedList<Connection>();

  private int numConnections = 0;

  /** Creates an SQL root entity which uses as many database connections as specified. */
  public SQLBasedEntity(AgentExecutionContext ctxt, int conns) {
    super(ctxt);
    this.numConnections = conns;
  }

  /** Returns the specified connection */
  public Connection getConnection(int index) {
    return connections.get(index);
  }

  /**
   * Call start to force a refresh of the entity tree
   *
   * @see com.ixora.rms.agents.impl.RootEntity#start()
   */
  public void start() throws Throwable {
    if (!isConnected()) {
      connect();
    }
  }

  /**
   * Disconnect, ignore errors
   *
   * @see com.ixora.rms.agents.impl.RootEntity#stop()
   */
  public void stop() throws Throwable {
    try {
      if (isConnected()) {
        disconnect();
      }
    } catch (Throwable e) {
      logger.error("Exception thrown while disconnecting: " + e.getMessage());
    }
  }

  /** Creates all database connections used for data collection */
  protected void connect() throws Throwable {
    // The context holds agent configuration and its custom data
    AgentConfiguration agentCfg = fContext.getAgentConfiguration();
    SQLODBCConfiguration cfg =
        (SQLODBCConfiguration) fContext.getAgentConfiguration().getAgentCustomConfiguration();

    // Create more connections to the same database
    for (int i = 0; i < numConnections; i++) {
      Connection conn =
          DriverManager.getConnection(cfg.getConnectionString(agentCfg.getMonitoredHost()));
      this.connections.add(conn);
    }
  }

  /** @return true if all connections are open */
  protected boolean isConnected() {
    if (connections.size() == 0) return false;

    boolean bConnected = true;
    try {
      for (Iterator<Connection> it = connections.iterator(); it.hasNext(); ) {
        Connection c = it.next();
        if (c.isClosed()) {
          bConnected = false;
          break;
        }
      }
    } catch (Exception e) {
      return false;
    }
    return bConnected;
  }

  /** Closes and discards all database connections */
  protected void disconnect() throws Throwable {
    for (Iterator<Connection> it = connections.iterator(); it.hasNext(); ) {
      Connection c = it.next();
      if (!c.isClosed()) c.close();
    }
    connections.clear();
  }

  /**
   * Ensures all database connections are present at the beginning of the cycle
   *
   * @see com.ixora.rms.agents.impl.EntityForest#beginCycle()
   */
  public void beginCycle() throws Throwable {
    // Connect if a connection was not already present
    if (!isConnected()) {
      connect();
    }

    // Refresh entities and their counters
    updateChildrenEntities(false);
  }

  /** @see com.ixora.rms.agents.impl.EntityForest#endCycle() */
  public void endCycle() throws Throwable {}
}
/** @author Daniel Moraru */
final class DashboardModelHelperImpl implements DashboardModelHelper {
  /** Logger */
  private static final AppLogger logger =
      AppLoggerFactory.getLogger(DashboardModelHelperImpl.class);

  /** Session model */
  private SessionModel model;

  /** Tuple class. */
  private static final class DataViewInfoData {
    private ResourceId context;
    private DataViewInfo info;
    /**
     * Constructor.
     *
     * @param context
     * @param dvinfo
     */
    public DataViewInfoData(ResourceId context, DataViewInfo dvinfo) {
      this.context = context;
      this.info = dvinfo;
    }

    public ResourceId getContext() {
      return context;
    }

    public DataViewInfo getInfo() {
      return info;
    }
  }

  /** Tuple class. */
  private static final class CounterInfoData {
    private ResourceId counterId;
    private CounterInfo info;
    /**
     * Constructor.
     *
     * @param counterId
     * @param cinfo
     */
    public CounterInfoData(ResourceId counterId, CounterInfo cinfo) {
      this.counterId = counterId;
      this.info = cinfo;
    }

    public ResourceId getContext() {
      return counterId;
    }

    public CounterInfo getInfo() {
      return info;
    }
  }

  /**
   * Constructor.
   *
   * @param model
   */
  DashboardModelHelperImpl(SessionModel model) {
    this.model = model;
  }

  /** @param context */
  public void rollbackDashboards(ResourceId context) {
    // rollback data views
    DataViewInfoData[] data = getDataViewInfoData(context);
    if (data != null) {
      ResourceId rid;
      DataViewInfoData d;
      DataViewInfo dvinfo;
      for (int i = 0; i < data.length; i++) {
        d = data[i];
        dvinfo = d.getInfo();
        rid = d.getContext();
        if (!dvinfo.isCommitted()) {
          model.getDataViewHelper().rollbackDataView(rid, dvinfo.getDataView().getName());
        }
      }
    }

    // rollback counters
    CounterInfoData[] counters = getCounterInfoData(context);
    if (!Utils.isEmptyArray(counters)) {
      // check that all counters are present
      for (CounterInfoData cid : counters) {
        model.getCounterHelper().rollbackCounter(cid.counterId, true);
      }
    }

    ArtefactInfoContainerImpl qc = model.getArtefactContainerImplForResource(context, true);
    if (qc == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find container for: " + context);
      }
      return;
    }
    Collection<DashboardInfoImpl> dis = qc.getDashboardInfoImpl();
    if (!Utils.isEmptyCollection(dis)) {
      for (DashboardInfoImpl di : dis) {
        di.rollback();
      }
    }
  }

  /**
   * Sets the dashboards associated with the given resource.
   *
   * @param id a valid, non regex resource id
   * @param q
   */
  public void setDashboards(ResourceId id, Dashboard[] groups) {
    ArtefactInfoContainerImpl qc = model.getArtefactContainerImplForResource(id, true);
    if (qc == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find query container for: " + id.toString());
      }
      return;
    }
    qc.setDashboards(groups);
    recalculateDashboardsStatus(id);
    model.refreshNode(id);
  }

  /**
   * Recalculates the enabled status of the given resource's dashboard by checking all queries
   * involved in each group. This has a non-aggressive search behaviour, i.e will only use counter
   * and data views that are already in the model as this is used very often when the dashboard
   * panel is refreshed.
   *
   * @param context
   */
  // the behaviour is as follows:
  // if the dashboard is not commited, the state will not be changed
  // else the state of the dasboard will be updated only if there is at least
  // one view already in the session model that belongs to this dashboard and
  // it is not enabled
  public void recalculateDashboardsStatus(ResourceId context) {
    ArtefactInfoContainerImpl acimpl = model.getArtefactContainerImplForResource(context, true);
    if (acimpl == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find container for: " + context);
      }
      return;
    }
    Collection<DashboardInfoImpl> cs = acimpl.getDashboardInfoImpl();
    if (cs == null) {
      return;
    }

    for (DashboardInfoImpl dinfo : cs) {
      if (dinfo.isCommitted()) {
        Dashboard db = dinfo.getDashboard();
        // flags to update
        boolean enabled = dinfo.getFlag(DashboardInfo.ENABLED);
        boolean plotted = dinfo.getFlag(DashboardInfo.ACTIVATED);
        boolean committed = dinfo.isCommitted();

        // check counters
        ResourceId[] counters = db.getCounters();
        if (!Utils.isEmptyArray(counters)) {
          // disable this dashboard only if one of it's counters
          // exists in the model and it's disabled
          for (ResourceId c : counters) {
            if (context != null) {
              c = c.complete(context);
            }
            CounterInfo cinfo = model.getCounterInfo(c, false);
            if (cinfo == null) {
              if (logger.isTraceEnabled()) {
                logger.error("Couldn't find counter: " + c);
              }
              break;
            }
            if (!cinfo.getFlag(CounterInfo.ENABLED)) {
              enabled = false;
            }
            if (!cinfo.getFlag(CounterInfo.ACTIVATED)) {
              plotted = false;
            }
            if (!cinfo.isCommitted()) {
              committed = false;
            }
          }
        }

        // check data views
        DataViewId[] views = db.getViews();
        if (!Utils.isEmptyArray(views)) {
          // disable this dashboard only if one of it's queries
          // exists in the model and it's disabled

          // find now info on every member
          DataViewId m;
          DataViewInfo dvinfo;
          for (int i = 0; i < views.length; i++) {
            m = views[i];
            if (context != null) {
              m = m.complete(context);
            }
            // refresh data views first
            model.getDataViewHelper().recalculateDataViewsStatus(m.getContext());
            dvinfo = model.getDataViewInfo(m, false);
            if (dvinfo == null) {
              // this query no longer exists...
              // ignore it with a warning in logs
              if (logger.isInfoEnabled()) {
                logger.error(
                    "Couldn't find view info for: "
                        + m
                        + ". Dashboard "
                        + dinfo.getTranslatedName()
                        + " will be incomplete.");
              }
              break;
            }
            // query exists and it will contribute to the state
            // of this dashboard
            if (!dvinfo.getFlag(QueryInfo.ENABLED)) {
              enabled = false;
            }
            if (!dvinfo.getFlag(QueryInfo.ACTIVATED)) {
              plotted = false;
            }
            if (!dvinfo.isCommitted()) {
              committed = false;
            }
          }
        }

        dinfo.setFlag(DashboardInfo.ENABLED, enabled);
        dinfo.setFlag(DashboardInfo.ACTIVATED, plotted);
        if (committed) {
          dinfo.commit();
        }
      } else {
        // just commit it
        dinfo.commit();
      }
    }
  }

  /**
   * Returns the view info data for all views in all the dashboards in the given context.
   *
   * @param context
   * @return
   */
  private DataViewInfoData[] getDataViewInfoData(ResourceId context) {
    ArtefactInfoContainerImpl ac = model.getArtefactContainerImplForResource(context, true);
    if (ac == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find artefact container for: " + context.toString());
      }
      return null;
    }
    Collection<DashboardInfo> cs = ac.getDashboardInfo();
    if (cs == null) {
      return null;
    }
    List<DataViewInfoData> ret = new LinkedList<DataViewInfoData>();
    for (DashboardInfo dinfo : cs) {
      DataViewInfoData[] views = getDataViewInfoData(context, dinfo.getDashboard().getName());
      if (views != null) {
        ret.addAll(Arrays.asList(views));
      }
    }
    return ret.toArray(new DataViewInfoData[ret.size()]);
  }

  /**
   * Returns the view info for all views in the given group in the given context.
   *
   * @param context
   * @param dbName
   * @return
   */
  private DataViewInfoData[] getDataViewInfoData(ResourceId context, String dbName) {
    DashboardInfo dinfo = model.getDashboardInfo(new DashboardId(context, dbName), true);
    if (dinfo == null) {
      return null;
    }
    List<DataViewInfoData> ret = new LinkedList<DataViewInfoData>();
    Dashboard db = dinfo.getDashboard();
    DataViewId[] views = db.getViews();
    if (views == null) {
      return null;
    }
    // find now query info on every member query
    DataViewId m;
    DataViewInfo dvinfo;
    for (int i = 0; i < views.length; i++) {
      m = views[i];
      if (context != null) {
        m = m.complete(context);
      }
      dvinfo = model.getDataViewInfo(m, true);
      if (dvinfo == null) {
        if (logger.isTraceEnabled()) {
          logger.error("Dataview " + m + " not found for dashboard " + db.getName());
        }
        continue;
      }
      ret.add(new DataViewInfoData(m.getContext(), dvinfo));
    }
    return (DataViewInfoData[]) ret.toArray(new DataViewInfoData[ret.size()]);
  }

  /**
   * Returns the view info for all counters that are part of the given dashboard
   *
   * @param context
   * @param dbName
   * @return
   */
  private CounterInfoData[] getCounterInfoData(ResourceId context, String dbName) {
    DashboardInfo dinfo = model.getDashboardInfo(new DashboardId(context, dbName), true);
    if (dinfo == null) {
      return null;
    }
    List<CounterInfoData> ret = new LinkedList<CounterInfoData>();
    Dashboard db = dinfo.getDashboard();
    ResourceId[] counters = db.getCounters();
    if (counters == null) {
      return null;
    }
    // find now query info on every member query
    ResourceId m;
    CounterInfo cinfo;
    for (int i = 0; i < counters.length; i++) {
      m = counters[i];
      if (context != null) {
        m = m.complete(context);
      }
      cinfo = model.getCounterInfo(m, true);
      if (cinfo == null) {
        if (logger.isTraceEnabled()) {
          logger.error("Counter " + m + " not found for dashboard " + db.getName());
        }
        continue;
      }
      ret.add(new CounterInfoData(m, cinfo));
    }
    return ret.toArray(new CounterInfoData[ret.size()]);
  }

  /**
   * Returns the counter info for all counters for all dashboards in the given context
   *
   * @param context
   * @param dbName
   * @return
   */
  private CounterInfoData[] getCounterInfoData(ResourceId context) {
    ArtefactInfoContainerImpl ac = model.getArtefactContainerImplForResource(context, true);
    if (ac == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find query group container for: " + context.toString());
      }
      return null;
    }
    Collection<DashboardInfo> cs = ac.getDashboardInfo();
    if (cs == null) {
      return null;
    }
    List<CounterInfoData> ret = new LinkedList<CounterInfoData>();
    for (DashboardInfo dinfo : cs) {
      CounterInfoData[] counters = getCounterInfoData(context, dinfo.getDashboard().getName());
      if (counters != null) {
        ret.addAll(Arrays.asList(counters));
      }
    }
    return ret.toArray(new CounterInfoData[ret.size()]);
  }

  /**
   * Sets the flag for the given dashboard.
   *
   * @param flag
   * @param context
   * @param dbName
   * @param value
   * @param commit
   */
  public void setDashboardFlag(
      int flag, ResourceId context, String dbName, boolean value, boolean commit) {
    // get views first
    DataViewInfoData[] data = getDataViewInfoData(context, dbName);
    if (data != null) {
      ResourceId rid;
      DataViewInfoData d;
      DataViewInfo dvinfo;
      for (int i = 0; i < data.length; i++) {
        d = data[i];
        dvinfo = d.getInfo();
        rid = d.getContext();
        model
            .getDataViewHelper()
            .setDataViewFlag(flag, rid, dvinfo.getDataView().getName(), value, commit);
      }
    }

    // now work with counters
    CounterInfoData[] counters = getCounterInfoData(context, dbName);
    if (!Utils.isEmptyArray(counters)) {
      // check that all counters are present
      for (CounterInfoData cid : counters) {
        ResourceInfo cInfo = model.getCounterHelper().getCounterInfo(cid.counterId);
        if (cInfo != null) {
          switch (flag) {
            case DashboardInfo.ENABLED:
              // if enabled is false then change the flag only for
              // counters which are not committed (this is to avoid a query
              // disabling the commited counters of another one)
              // @see QueryRealizerLiveSession for an excuse
              if (value || !cInfo.getCounterInfo().isCommitted()) {
                model
                    .getCounterHelper()
                    .setCounterFlag(cid.counterId, CounterInfo.ENABLED, value, true);
              }
              break;
            case DashboardInfo.ACTIVATED:
              model
                  .getCounterHelper()
                  .setCounterFlag(cid.counterId, CounterInfo.ACTIVATED, value, true);
          }
        }
      }
    }

    ArtefactInfoContainerImpl ac = model.getArtefactContainerImplForResource(context, true);
    if (ac == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find container for dashboard " + context);
      }
      return;
    }

    // enable the dashboard
    ac.setDashboardFlag(flag, dbName, value, commit);
    // refresh context node
    model.refreshNode(context);
  }

  /**
   * @see com.ixora.rms.client.model.DashboardModelHelper#addDashboard(com.ixora.rms.ResourceId,
   *     com.ixora.rms.repository.QueryGroup)
   */
  public void addDashboard(ResourceId id, Dashboard group) {
    ArtefactInfoContainerImpl ac = model.getArtefactContainerImplForResource(id, false);
    if (ac == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find container for: " + id);
      }
      return;
    }
    ac.addDashboard(group);
    recalculateDashboardsStatus(id);
    model.refreshNode(id);
  }

  /**
   * @see com.ixora.rms.client.model.DashboardModelHelper#removeDashboard(com.ixora.rms.ResourceId,
   *     java.lang.String)
   */
  public void removeDashboard(ResourceId id, String dbName) {
    ArtefactInfoContainerImpl ac = model.getArtefactContainerImplForResource(id, false);
    if (ac == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find container for: " + id);
      }
      return;
    }
    ac.removeDashboard(dbName);
    model.refreshNode(id);
  }

  /** @see com.ixora.rms.client.model.DashboardModelHelper#getAllDashboardsToRealize() */
  @SuppressWarnings("unchecked")
  public Map<ResourceId, Collection<DashboardInfo>> getAllDashboardsToRealize() {
    Map<ResourceId, Collection<DashboardInfo>> ret =
        new HashMap<ResourceId, Collection<DashboardInfo>>();
    SessionNode sn = model.getSessionNode();
    Enumeration<ResourceNode> e = sn.breadthFirstEnumeration();
    ResourceNode rn;
    while (e.hasMoreElements()) {
      rn = e.nextElement();
      // get the realizable dashboards
      Collection<DashboardInfo> col = sn.getArtefactInfoContainer().getDashboardsToRealize();
      if (col != null) {
        ResourceId rid = rn.getResourceId();
        ret.put(rid, col);
      }
    }
    return ret;
  }

  /** @see com.ixora.rms.client.model.DashboardModelHelper#getAllDashboardsToUnRealize() */
  @SuppressWarnings("unchecked")
  public Map<ResourceId, Collection<DashboardInfo>> getAllDashboardsToUnRealize() {
    Map<ResourceId, Collection<DashboardInfo>> ret =
        new HashMap<ResourceId, Collection<DashboardInfo>>();
    SessionNode sn = model.getSessionNode();
    Enumeration<ResourceNode> e = sn.breadthFirstEnumeration();
    ResourceNode rn;
    while (e.hasMoreElements()) {
      rn = e.nextElement();
      // get the unrealizable dashboards
      Collection<DashboardInfo> col = sn.getArtefactInfoContainer().getDashboardsToUnRealize();
      if (col != null) {
        ResourceId rid = rn.getResourceId();
        ret.put(rid, col);
      }
    }
    return ret;
  }

  /**
   * @see
   *     com.ixora.rms.client.model.DashboardModelHelper#isDashboardReady(com.ixora.rms.internal.ResourceId,
   *     com.ixora.rms.repository.QueryGroup)
   */
  public boolean isDashboardReady(ResourceId context, Dashboard dashboard) {
    boolean ready = true;
    ResourceId[] counters = dashboard.getCounters();
    if (!Utils.isEmptyArray(counters)) {
      // check that all counters are present
      for (ResourceId c : counters) {
        if (context != null) {
          c = c.complete(context);
        }
        CounterInfo cinfo = model.getCounterInfo(c, true);
        if (cinfo == null) {
          return false;
        }
      }
    }

    // now check that all views are ready
    DataViewId[] views = dashboard.getViews();
    if (ready && !Utils.isEmptyArray(views)) {
      // find now query info on every member query
      for (DataViewId m : views) {
        if (context != null) {
          m = m.complete(context);
        }
        DataViewInfo dvinfo = model.getDataViewInfo(m, true);
        if (dvinfo == null) {
          return false;
        }
        if (!model
            .getQueryHelper()
            .isQueryReady(m.getContext(), dvinfo.getDataView().getQueryDef())) {
          return false;
        }
      }
    }
    return ready;
  }

  /**
   * @see
   *     com.ixora.rms.client.model.DashboardModelHelper#commitDashboard(com.ixora.rms.internal.ResourceId,
   *     java.lang.String)
   */
  public void commitDashboard(ResourceId context, String dashboard) {
    ArtefactInfoContainerImpl qc = model.getArtefactContainerImplForResource(context, true);
    if (qc == null) {
      return;
    }
    DashboardInfoImpl di = qc.getDashboardInfoImpl(dashboard);
    if (di == null) {
      if (logger.isTraceEnabled()) {
        logger.error("Couldn't find dashboard info for: " + di);
      }
      return;
    }
    di.commit();
  }

  /** @see com.ixora.rms.client.model.DashboardModelHelper#getAllCommittedDashboards(int) */
  @SuppressWarnings("unchecked")
  public Collection<DashboardId> getAllCommittedDashboards(int flag) {
    Collection<DashboardId> ret = new LinkedList<DashboardId>();
    Enumeration<SessionModelTreeNode> e = model.getSessionNode().breadthFirstEnumeration();
    while (e.hasMoreElements()) {
      SessionModelTreeNode sn = (SessionModelTreeNode) e.nextElement();
      Collection<DashboardInfo> dashboards = sn.getArtefactInfoContainer().getDashboardInfo();
      if (!Utils.isEmptyCollection(dashboards)) {
        for (DashboardInfo di : dashboards) {
          if (di.isCommitted() && di.getFlag(flag)) {
            ret.add(new DashboardId(sn.getResourceId(), di.getDashboard().getName()));
          }
        }
      }
    }
    return ret;
  }
}
/**
 * Dialog for displaying exceptions in a production environment.
 *
 * @author Daniel Moraru
 */
final class ShowAboutDialog extends AppDialog {
  private static final long serialVersionUID = 6771473584688621946L;
  /** Logger */
  private static final AppLogger logger = AppLoggerFactory.getLogger(ShowAboutDialog.class);
  /** HTML pane */
  private JEditorPane htmlPane;
  /** Event handler */
  private EventHandler eventHandler;

  private final class EventHandler implements HyperlinkListener {
    /**
     * @see javax.swing.event.HyperlinkListener#hyperlinkUpdate(javax.swing.event.HyperlinkEvent)
     */
    public void hyperlinkUpdate(HyperlinkEvent e) {
      if (e.getEventType() == EventType.ACTIVATED) {
        handleSeeURL(e.getURL());
      }
    }
  }

  /** ShowExceptionDialog constructor comment. */
  public ShowAboutDialog() {
    super(VERTICAL);
    initialize();
  }

  /**
   * ShowExceptionDialog constructor comment.
   *
   * @param owner java.awt.Dialog
   */
  public ShowAboutDialog(Dialog owner) {
    super(owner, VERTICAL);
    initialize();
  }

  /**
   * ShowExceptionDialog constructor comment.
   *
   * @param owner java.awt.Frame
   * @param eh
   */
  public ShowAboutDialog(Frame owner) {
    super(owner, VERTICAL);
    initialize();
  }

  /** @see com.ixora.common.ui.AppDialog#getDisplayPanels() */
  protected Component[] getDisplayPanels() {
    return new Component[] {htmlPane};
  }

  /** Initializes this dialog. */
  private void initialize() {
    this.fPadding = 0;
    this.eventHandler = new EventHandler();
    setTitle(MessageRepository.get(Msg.COMMON_UI_TEXT_ABOUT));
    setPreferredSize(new Dimension(396, 570));
    htmlPane = UIFactoryMgr.createHtmlPane();
    htmlPane.addHyperlinkListener(this.eventHandler);

    // fill in the table with deployment modules and their versions
    StringBuffer components = new StringBuffer(100);
    Module[] modules = UpdateMgr.getAllRegisteredModules();
    if (modules != null) {
      components.append("<br>");
      for (int i = 0; i < modules.length; i++) {
        Module module = modules[i];
        components.append(module.getName());
        components.append("(");
        components.append(module.getVersion());
        components.append(")");
        if (i != modules.length - 1) {
          components.append(", ");
        }
      }
    }
    StringBuffer jvm = new StringBuffer();
    jvm.append(System.getProperty("java.vendor"))
        .append(" ")
        .append(System.getProperty("java.version"));
    StringBuffer os = new StringBuffer();
    os.append(System.getProperty("os.name")).append(" ").append(System.getProperty("os.version"));

    Calendar cal = Calendar.getInstance();
    cal.setTime(new Date());
    int year = cal.get(Calendar.YEAR);

    htmlPane.setText(
        MessageRepository.get(
            Msg.COMMON_UI_TEXT_ABOUT_DOCUMENT,
            new String[] {
              Product.getProductInfo().getVersion().toString(), // version
              String.valueOf(year), // year
              components.toString(), //  components
              jvm.toString(), // JVM
              os.toString()
            })); // OS
    htmlPane.setBorder(null);
    buildContentPane();
  }

  /**
   * Overridden to remove border.
   *
   * @see com.ixora.common.ui.AppDialog#getJDialogContentPane()
   */
  protected JPanel getJDialogContentPane() {
    JPanel ret = super.getJDialogContentPane();
    // remove border
    ret.setBorder(null);
    return ret;
  }

  /**
   * Shows the dialog.
   *
   * @param parent the parent component
   */
  public static void showDialog(Window parent) {
    try {
      ShowAboutDialog aShowAboutDialog;
      if (parent instanceof Dialog) {
        aShowAboutDialog = new ShowAboutDialog((Dialog) parent);
      } else {
        if (parent instanceof Frame) {
          aShowAboutDialog = new ShowAboutDialog((Frame) parent);
        } else {
          aShowAboutDialog = new ShowAboutDialog();
        }
      }
      aShowAboutDialog.setModal(true);
      UIUtils.centerDialogAndShow(parent, aShowAboutDialog);
    } catch (Exception e) {
      UIExceptionMgr.userException(e);
    }
  }

  /** @see com.ixora.common.ui.AppDialog#getButtons() */
  @SuppressWarnings("serial")
  protected JButton[] getButtons() {
    JButton close =
        UIFactoryMgr.createButton(
            new ActionClose() {
              public void actionPerformed(ActionEvent e) {
                try {
                  dispose();
                } catch (Exception ex) {
                  logger.error(ex);
                }
              }
            });
    return new JButton[] {close};
  }

  /** Launches the external browser with the given url. */
  private void handleSeeURL(URL url) {
    try {
      Utils.launchBrowser(url);
    } catch (Throwable e) {
      UIExceptionMgr.userException(e);
    }
  }
}