/* (non-Javadoc)
   * @see com.mvplite.view.NavigationController#setStartView(com.mvplite.view.NavigateableView)
   */
  @Override
  public void setStartView(NavigateableView view) {
    HistoryEntry entry = new HistoryEntry();
    entry.eventsToFire = calculateEventsToFireList(view);

    historyStack.put("", entry);
  }
Beispiel #2
0
  /**
   * Get the history after a specified revision.
   *
   * <p>The default implementation first fetches the full history and then throws away the oldest
   * revisions. This is not efficient, so subclasses should override it in order to get good
   * performance. Once every subclass has implemented a more efficient method, the default
   * implementation should be removed and made abstract.
   *
   * @param file the file to get the history for
   * @param sinceRevision the revision right before the first one to return, or {@code null} to
   *     return the full history
   * @return partial history for file
   * @throws HistoryException on error accessing the history
   */
  History getHistory(File file, String sinceRevision) throws HistoryException {

    // If we want an incremental history update and get here, warn that
    // it may be slow.
    if (sinceRevision != null) {
      Logger logger = OpenGrokLogger.getLogger();
      logger.log(
          Level.WARNING,
          "Incremental history retrieval is not implemented for {0}.",
          getClass().getSimpleName());
      logger.log(Level.WARNING, "Falling back to slower full history retrieval.");
    }

    History history = getHistory(file);

    if (sinceRevision == null) {
      return history;
    }

    List<HistoryEntry> partial = new ArrayList<>();
    for (HistoryEntry entry : history.getHistoryEntries()) {
      partial.add(entry);
      if (sinceRevision.equals(entry.getRevision())) {
        // Found revision right before the first one to return.
        break;
      }
    }

    removeAndVerifyOldestChangeset(partial, sinceRevision);
    history.setHistoryEntries(partial);
    return history;
  }
  /**
   * Get a map from author names to their ids in the database. The authors that are not in the
   * database are added to it.
   *
   * @param conn the connection to the database
   * @param history the history to get the author names from
   * @param reposId the id of the repository
   * @return a map from author names to author ids
   */
  private Map<String, Integer> getAuthors(ConnectionResource conn, History history, int reposId)
      throws SQLException {
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    PreparedStatement ps = conn.getStatement(GET_AUTHORS);
    ps.setInt(1, reposId);
    try (ResultSet rs = ps.executeQuery()) {
      while (rs.next()) {
        map.put(rs.getString(1), rs.getInt(2));
      }
    }

    PreparedStatement insert = conn.getStatement(ADD_AUTHOR);
    insert.setInt(1, reposId);
    for (HistoryEntry entry : history.getHistoryEntries()) {
      String author = entry.getAuthor();
      if (!map.containsKey(author)) {
        int id = nextAuthorId.getAndIncrement();
        insert.setString(2, author);
        insert.setInt(3, id);
        insert.executeUpdate();
        map.put(author, id);
        conn.commit();
      }
    }

    return map;
  }
Beispiel #4
0
  /**
   * Update the history store with the value of an an read, write or execute operation. Also, the
   * timestamp of the insertion is recorded. Also, the recorded history values are added to the
   * given json value.
   *
   * @param pJmxReq request for which an entry should be added in this history store
   * @param pJson the JSONObject to which to add the history.
   */
  public synchronized void updateAndAdd(JmxRequest pJmxReq, JSONObject pJson) {
    long timestamp = System.currentTimeMillis() / 1000;
    pJson.put(KEY_TIMESTAMP, timestamp);

    JmxRequest.Type type = pJmxReq.getType();
    if (type == EXEC || type == WRITE) {
      HistoryEntry entry = historyStore.get(new HistoryKey(pJmxReq));
      if (entry != null) {
        synchronized (entry) {
          // A history data to json object for the response
          pJson.put(KEY_HISTORY, entry.jsonifyValues());

          // Update history for next time
          if (type == EXEC) {
            entry.add(pJson.get(KEY_VALUE), timestamp);
          } else if (type == WRITE) {
            // The new value to set as string representation
            entry.add(pJmxReq.getValue(), timestamp);
          }
        }
      }
    } else if (type == READ) {
      updateReadHistory(pJmxReq, pJson, timestamp);
    }
  }
 /** Populate recent bookmarks. */
 public void populateRecentBookmarks() {
   JMenu bookmarksMenu = this.recentBookmarksMenu;
   bookmarksMenu.removeAll();
   Collection<HistoryEntry<BookmarkInfo>> historyEntries =
       BookmarksHistory.getInstance().getRecentEntries(PREFERRED_MAX_MENU_SIZE);
   for (HistoryEntry<BookmarkInfo> hentry : historyEntries) {
     BookmarkInfo binfo = hentry.getItemInfo();
     String text = binfo.getTitle();
     URL url = binfo.getUrl();
     String urlText = url.toExternalForm();
     if ((text == null) || (text.length() == 0)) {
       text = urlText;
     }
     long elapsed = System.currentTimeMillis() - hentry.getTimetstamp();
     text = text + " (" + Timing.getElapsedText(elapsed) + " ago)";
     Action action = this.actionPool.createBookmarkNavigateAction(url);
     JMenuItem menuItem = ComponentSource.menuItem(text, action);
     StringBuffer toolTipText = new StringBuffer();
     toolTipText.append("<html>");
     toolTipText.append(urlText);
     String description = binfo.getDescription();
     if ((description != null) && (description.length() != 0)) {
       toolTipText.append("<br>");
       toolTipText.append(description);
     }
     menuItem.setToolTipText(toolTipText.toString());
     bookmarksMenu.add(menuItem);
   }
 }
  /** Helper for {@link #get(File, Repository)}. */
  private History getHistory(File file, Repository repository, boolean withFiles)
      throws HistoryException, SQLException {
    final String filePath = getSourceRootRelativePath(file);
    final String reposPath = toUnixPath(repository.getDirectoryName());
    final ArrayList<HistoryEntry> entries = new ArrayList<HistoryEntry>();
    final ConnectionResource conn = connectionManager.getConnectionResource();
    try {
      final PreparedStatement ps;
      if (file.isDirectory()) {
        // Fetch history for all files under this directory.
        ps = conn.getStatement(GET_DIR_HISTORY);
        ps.setString(2, filePath);
      } else {
        // Fetch history for a single file only.
        ps = conn.getStatement(GET_FILE_HISTORY);
        ps.setString(2, getParentPath(filePath));
        ps.setString(3, getBaseName(filePath));
      }
      ps.setString(1, reposPath);

      final PreparedStatement filePS = withFiles ? conn.getStatement(GET_CS_FILES) : null;

      try (ResultSet rs = ps.executeQuery()) {
        while (rs.next()) {
          // Get the information about a changeset
          String revision = rs.getString(1);
          String author = rs.getString(2);
          Timestamp time = rs.getTimestamp(3);
          String message = rs.getString(4);
          HistoryEntry entry = new HistoryEntry(revision, time, author, null, message, true);
          entries.add(entry);

          // Fill the list of files touched by the changeset, if
          // requested.
          if (withFiles) {
            int changeset = rs.getInt(5);
            filePS.setInt(1, changeset);
            try (ResultSet fileRS = filePS.executeQuery()) {
              while (fileRS.next()) {
                entry.addFile(fileRS.getString(1));
              }
            }
          }
        }
      }
    } finally {
      connectionManager.releaseConnection(conn);
    }

    History history = new History();
    history.setHistoryEntries(entries);

    RuntimeEnvironment env = RuntimeEnvironment.getInstance();
    if (env.isTagsEnabled() && repository.hasFileBasedTags()) {
      repository.assignTagsInHistory(history);
    }

    return history;
  }
Beispiel #7
0
 /**
  * Set the global maximum limit for history entries
  *
  * @param pGlobalMaxEntries limit
  */
 public synchronized void setGlobalMaxEntries(int pGlobalMaxEntries) {
   globalMaxEntries = pGlobalMaxEntries;
   // Refresh all entries
   for (HistoryEntry entry : historyStore.values()) {
     entry.setMaxEntries(globalMaxEntries);
     entry.trim();
   }
 }
Beispiel #8
0
 private void addAttributeFromSingleValue(
     JSONObject pHistMap, String pAttrName, HistoryKey pKey, Object pValue, long pTimestamp) {
   HistoryEntry entry = getEntry(pKey, pValue, pTimestamp);
   if (entry != null) {
     synchronized (entry) {
       pHistMap.put(pAttrName, entry.jsonifyValues());
       entry.add(pValue, pTimestamp);
     }
   }
 }
Beispiel #9
0
  /**
   * Remove the oldest changeset from a list (assuming sorted with most recent changeset first) and
   * verify that it is the changeset we expected to find there.
   *
   * @param entries a list of {@code HistoryEntry} objects
   * @param revision the revision we expect the oldest entry to have
   * @throws HistoryException if the oldest entry was not the one we expected
   */
  void removeAndVerifyOldestChangeset(List<HistoryEntry> entries, String revision)
      throws HistoryException {
    HistoryEntry entry = entries.isEmpty() ? null : entries.remove(entries.size() - 1);

    // TODO We should check more thoroughly that the changeset is the one
    // we expected it to be, since some SCMs may change the revision
    // numbers so that identical revision numbers does not always mean
    // identical changesets. We could for example get the cached changeset
    // and compare more fields, like author and date.
    if (entry == null || !revision.equals(entry.getRevision())) {
      throw new HistoryException(
          "Cached revision '" + revision + "' not found in the repository " + getDirectoryName());
    }
  }
 private void writeComposite(
     final Element res,
     final VirtualFile file,
     final EditorWithProviderComposite composite,
     final boolean pinned,
     final EditorWithProviderComposite selectedEditor) {
   final Element fileElement = new Element("file");
   fileElement.setAttribute("leaf-file-name", file.getName()); // TODO: all files
   final HistoryEntry entry = composite.currentStateAsHistoryEntry();
   entry.writeExternal(fileElement, getManager().getProject());
   fileElement.setAttribute("pinned", Boolean.toString(pinned));
   fileElement.setAttribute(
       "current", Boolean.toString(composite.equals(getManager().getLastSelected())));
   fileElement.setAttribute("current-in-tab", Boolean.toString(composite.equals(selectedEditor)));
   res.addContent(fileElement);
 }
Beispiel #11
0
 private HistoryEntry getEntry(HistoryKey pKey, Object pValue, long pTimestamp) {
   HistoryEntry entry = historyStore.get(pKey);
   if (entry != null) {
     return entry;
   }
   // Now try all known patterns and add lazily the key
   for (HistoryKey key : patterns.keySet()) {
     if (key.matches(pKey)) {
       entry = new HistoryEntry(patterns.get(key));
       entry.add(pValue, pTimestamp);
       historyStore.put(pKey, entry);
       return entry;
     }
   }
   return null;
 }
  /* (non-Javadoc)
   * @see com.mvplite.view.NavigationController#setCurrentView(com.mvplite.view.NavigateableView)
   */
  @Override
  public void setCurrentView(NavigateableView view) {

    if (!setCurrentViewCausedByHistoryChange) {
      // Add url fragmentHistory support
      String uriFragment = calculateUri(view);
      HistoryEntry entry = new HistoryEntry();
      entry.eventsToFire = calculateEventsToFireList(view);

      if (historyStack.isEmpty()) historyStack.put("", entry);

      historyStack.put(uriFragment, entry);
      page.setUriFragment(uriFragment, false); // Seems not to work at first call
    }
    fireNavigatedTo(view);
  }
 private void logEntries(Collection<HistoryEntry> entries) {
   LocalHistory.LOG.log(Level.FINE, "LocalHistory returns {0} entries", entries.size()); // NOI18N
   if (LocalHistory.LOG.isLoggable(Level.FINEST)) {
     StringBuilder sb = new StringBuilder();
     Iterator<HistoryEntry> it = entries.iterator();
     while (it.hasNext()) {
       HistoryEntry entry = it.next();
       sb.append("["); // NOI18N
       sb.append(DateFormat.getDateTimeInstance().format(entry.getDateTime()));
       sb.append(",["); // NOI18N
       sb.append(toString(entry.getFiles()));
       sb.append("]]"); // NOI18N
       if (it.hasNext()) sb.append(","); // NOI18N
     }
     LocalHistory.LOG.finest(sb.toString());
   }
 }
  /**
   * Build maps from directory names and file names to their respective identifiers in the database.
   * The directories and files that are not already in the database, are added to it.
   *
   * @param conn the connection to the database
   * @param history the history to get the file and directory names from
   * @param reposId the id of the repository
   * @param dirMap a map which will be filled with directory names and ids
   * @param fileMap a map which will be filled with file names and ids
   */
  private void getFilesAndDirectories(
      ConnectionResource conn,
      History history,
      int reposId,
      Map<String, Integer> dirMap,
      Map<String, Integer> fileMap)
      throws SQLException {

    populateFileOrDirMap(conn.getStatement(GET_DIRS), reposId, dirMap);
    populateFileOrDirMap(conn.getStatement(GET_FILES), reposId, fileMap);

    int insertCount = 0;

    PreparedStatement insDir = conn.getStatement(INSERT_DIR);
    PreparedStatement insFile = conn.getStatement(INSERT_FILE);
    for (HistoryEntry entry : history.getHistoryEntries()) {
      for (String file : entry.getFiles()) {
        String fullPath = toUnixPath(file);
        // Add the file to the database and to the map if it isn't
        // there already. Assumption: If the file is in the database,
        // all its parent directories are also there.
        if (!fileMap.containsKey(fullPath)) {
          // Get the dir id for this file, potentially adding the
          // parent directories to the db and to dirMap.
          int dir = addAllDirs(insDir, reposId, fullPath, dirMap);
          int fileId = nextFileId.getAndIncrement();
          insFile.setInt(1, dir);
          insFile.setString(2, getBaseName(fullPath));
          insFile.setInt(3, fileId);
          insFile.executeUpdate();
          fileMap.put(fullPath, fileId);

          // Commit every now and then to allow the database to free
          // resources (like locks and transaction log), but not too
          // frequently, since that may kill the performance. It is
          // OK not to commit for every file added, since the worst
          // thing that could happen is that we need to re-insert
          // the files added since the last commit in case of a crash.
          insertCount++;
          if (insertCount % 30 == 0) {
            conn.commit();
          }
        }
      }
    }
  }
Beispiel #15
0
  @Override
  public ASerializedView getSerializableRepresentation() {
    SerializedRadialHierarchyView serializedForm = new SerializedRadialHierarchyView(this);
    serializedForm.setMaxDisplayedHierarchyDepth(iMaxDisplayedHierarchyDepth);
    serializedForm.setNewSelection(bIsNewSelection);
    serializedForm.setDefaultDrawingStrategyType(
        drawingStrategyManager.getDefaultDrawingStrategy().getDrawingStrategyType());

    ADrawingState currentDrawingState = drawingController.getCurrentDrawingState();

    if (pdCurrentRootElement != null) {
      if ((currentDrawingState.getType() == EDrawingStateType.DRAWING_STATE_DETAIL_OUTSIDE)
          || (currentDrawingState.getType() == EDrawingStateType.DRAWING_STATE_FULL_HIERARCHY)) {

        serializedForm.setDrawingStateType(currentDrawingState.getType());
        serializedForm.setRootElementID(pdCurrentRootElement.getElementID());
        serializedForm.setSelectedElementID(pdCurrentSelectedElement.getElementID());
        serializedForm.setRootElementStartAngle(pdCurrentRootElement.getCurrentStartAngle());
        serializedForm.setSelectedElementStartAngle(
            pdCurrentSelectedElement.getCurrentStartAngle());
      } else {
        HistoryEntry historyEntry = navigationHistory.getCurrentHistoryEntry();
        serializedForm.setDrawingStateType(historyEntry.getDrawingState().getType());
        serializedForm.setRootElementID(historyEntry.getRootElement().getElementID());
        serializedForm.setSelectedElementID(historyEntry.getSelectedElement().getElementID());
        serializedForm.setRootElementStartAngle(historyEntry.getRootElementStartAngle());
        serializedForm.setSelectedElementStartAngle(historyEntry.getSelectedElementStartAngle());
      }
    }

    return serializedForm;
  }
Beispiel #16
0
  /**
   * Configure the history length for a specific entry. If the length is 0 disable history for this
   * key
   *
   * @param pKey history key
   * @param pMaxEntries number of maximal entries. If larger than globalMaxEntries, then
   *     globalMaxEntries is used instead.
   */
  public synchronized void configure(HistoryKey pKey, int pMaxEntries) {
    int maxEntries = pMaxEntries > globalMaxEntries ? globalMaxEntries : pMaxEntries;

    // Remove entries if set to 0
    if (pMaxEntries == 0) {
      removeEntries(pKey);
      return;
    }
    if (pKey.isMBeanPattern()) {
      patterns.put(pKey, maxEntries);
      // Trim all already stored keys
      for (HistoryKey key : historyStore.keySet()) {
        if (pKey.matches(key)) {
          HistoryEntry entry = historyStore.get(key);
          entry.setMaxEntries(maxEntries);
          entry.trim();
        }
      }
    } else {
      HistoryEntry entry = historyStore.get(pKey);
      if (entry != null) {
        entry.setMaxEntries(maxEntries);
        entry.trim();
      } else {
        entry = new HistoryEntry(maxEntries);
        historyStore.put(pKey, entry);
      }
    }
  }
Beispiel #17
0
  // @Override
  public View getView(int inPos, View vwConvert, ViewGroup parent) {
    View vwView;
    if (vwConvert == null) {
      vwView = mInflater.inflate(R.layout.history_item, parent, false);
    } else {
      vwView = vwConvert;
    }

    TextView txtvExpr = (TextView) vwView.findViewById(R.id.historyExpr);
    TextView txtvResult = (TextView) vwView.findViewById(R.id.historyResult);

    HistoryEntry entry = mEntries.elementAt(inPos);
    String base = entry.getBase();
    txtvExpr.setText(entry.getBase());

    try {
      String strRes = mEval.evaluate(base);
      txtvResult.setText("= " + strRes);
    } catch (SyntaxException e) {
      txtvResult.setText("");
    }

    return vwView;
  }
Beispiel #18
0
 /**
  * Assign tags to changesets they represent The complete list of tags must be pre-built using
  * {@code getTagList()}. Then this function squeeze all tags to changesets which actually exist in
  * the history of given file. Must be implemented repository-specific.
  *
  * @see getTagList
  * @param hist History we want to assign tags to.
  */
 void assignTagsInHistory(History hist) throws HistoryException {
   if (hist == null) {
     return;
   }
   if (this.getTagList() == null) {
     throw new HistoryException("Tag list was not created before assigning tags to changesets!");
   }
   Iterator<TagEntry> it = this.getTagList().descendingIterator();
   TagEntry lastTagEntry = null;
   // Go through all commits of given file
   for (HistoryEntry ent : hist.getHistoryEntries()) {
     // Assign all tags created since the last revision
     // Revision in this HistoryEntry must be already specified!
     // TODO is there better way to do this? We need to "repeat"
     // last element returned by call to next()
     while (lastTagEntry != null || it.hasNext()) {
       if (lastTagEntry == null) {
         lastTagEntry = it.next();
       }
       if (lastTagEntry.compareTo(ent) >= 0) {
         if (ent.getTags() == null) {
           ent.setTags(lastTagEntry.getTags());
         } else {
           ent.setTags(ent.getTags() + ", " + lastTagEntry.getTags());
         }
       } else {
         break;
       }
       if (it.hasNext()) {
         lastTagEntry = it.next();
       } else {
         lastTagEntry = null;
       }
     }
   }
 }
Beispiel #19
0
  public View getView(int position, View convertView, ViewGroup parent) {
    View view;
    if (convertView == null) {
      view = mInflater.inflate(R.layout.history_item, parent, false);
    } else {
      view = convertView;
    }

    TextView expr = (TextView) view.findViewById(R.id.historyExpr);
    TextView result = (TextView) view.findViewById(R.id.historyResult);

    HistoryEntry entry = mEntries.elementAt(position);
    String base = entry.getBase();
    expr.setText(entry.getBase());

    try {
      String res = mEval.evaluate(base);
      result.setText("= " + res);
    } catch (SyntaxException e) {
      result.setText("");
    }

    return view;
  }
Beispiel #20
0
  /**
   * {@inheritDoc}
   *
   * @param figureId The id of the {@link Figure}.
   * @param clientId The id of the {@link Figure}s {@link Client owner}.
   * @param targetFieldNotation The {@link Field#getNotation() notation} of the {@link Field} the
   *     {@link Figure} wants to move to.
   * @param simpMessagingTemplate Template for sending websocket messages.
   * @throws MoveNotAllowedException
   */
  @Override
  public void performMovement(
      String figureId,
      String clientId,
      String targetFieldNotation,
      SimpMessagingTemplate simpMessagingTemplate)
      throws MoveNotAllowedException {
    // Only the current player is allowed to do moves.
    // Fixes CCD2015-50
    if (!clientId.equals(getCurrentPlayer().getId())) throw new MoveNotAllowedException();

    List<Hexagon> possibleMovements = getPossibleFieldsToMove(figureId);
    // Throw an exception when the client ID does not match the figures owner id
    // or when the target field is not in the list of possible moves.
    if (possibleMovements
                .stream()
                .filter(hexagon -> hexagon.getNotation().equals(targetFieldNotation))
                .count()
            == 0
        || getFigures()
                .stream()
                // Only figures, that are sill active.
                .filter(hexagonFigure -> !hexagonFigure.isRemoved())
                // Only figures equals to the given id
                .filter(hexagonFigure -> hexagonFigure.getId().equals(figureId))
                // Only the clients figures
                .filter(hexagonFigure -> hexagonFigure.getClient().getId().equals(clientId))
                .count()
            == 0) throw new MoveNotAllowedException();

    HistoryEntry historyEntry = new HistoryEntry();
    historyEntry.setPlayer(getCurrentPlayer());
    // Remove a figure from the chessboard if there is a figure on the target field
    getFigures()
        .stream()
        // Only figures, that are sill active.
        // Fixes CCD2015-52
        .filter(hexagonFigure -> !hexagonFigure.isRemoved())
        // Only figures on the target hexagon
        .filter(
            hexagonFigure -> hexagonFigure.getPosition().getNotation().equals(targetFieldNotation))
        .findFirst()
        .ifPresent(
            hexagonFigure -> {
              historyEntry
                  .getChessboardEvents()
                  .add(
                      new FigureEvent()
                          .setFigureId(hexagonFigure.getId())
                          .setEvent(FigureEvent.Event.REMOVED));
              hexagonFigure.setRemoved(true);
            });

    // Move our figure to the target field
    getFigures()
        .stream()
        // Only figures, that are sill active.
        .filter(hexagonFigure -> !hexagonFigure.isRemoved())
        // Only figures on the source hexagon
        .filter(hexagonFigure -> hexagonFigure.getId().equals(figureId))
        .findFirst()
        .ifPresent(
            hexagonFigure -> {
              historyEntry
                  .getChessboardEvents()
                  .add(
                      new MovementEvent()
                          .setFigureId(figureId)
                          .setFromNotation(hexagonFigure.getPosition().getNotation())
                          .setToNotation(targetFieldNotation));
              try {
                hexagonFigure.setPosition((Hexagon) getFieldByNotation(targetFieldNotation));
              } catch (NotationNotFoundException e) {
                logger.error("", e);
              }
            });
    // Add action to history
    getParentGame().getGameHistory().add(historyEntry);
    // Send event through websocket
    simpMessagingTemplate.convertAndSend("/game/" + getParentGame().getId(), historyEntry);
    // Change the active player and send it through websocket
    setCurrentPlayer(getCurrentPlayer().getNextClient());
    checkIfCurrentPlayerIsDefeated();
    while (getCurrentPlayer().isDefeated()) {
      setCurrentPlayer(getCurrentPlayer().getNextClient());
      checkIfCurrentPlayerIsDefeated();
    }
    getParentGame()
        .getPlayerList()
        .stream()
        .filter(client -> !client.isDefeated())
        .forEach(
            client -> {
              PlayerChangedEvent playerChangedEvent =
                  new PlayerChangedEvent().setItYouTurn(client.equals(getCurrentPlayer()));
              simpMessagingTemplate.convertAndSend(
                  "/game/" + getParentGame().getId() + "/" + client.getId(), playerChangedEvent);
            });
  }
  /** Test of parse method, of class ClearCaseHistoryParser. */
  @Test
  public void parseDirHistory() throws Exception {
    String author1 = "First Last (username)";
    String author2 = "First2 Last2 (username2)";
    String output =
        "create directory version\n"
            + "20050401.162902\n"
            + author1
            + "\n"
            + "/main/3\n"
            + "Removed directory element \"prototype\".\n"
            + ".\n"
            + "create directory version\n"
            + "20020618.215917\n"
            + author2
            + "\n"
            + "/main/2\n"
            + "Merge from wwwww for dddddd\n"
            + ".\n"
            + "create directory version\n"
            + "20010228.174617\n"
            + author1
            + "\n"
            + "/main/1\n"
            + "New structure.\n"
            + "\n"
            + "Added directory element \"generic\".\n"
            + "Added directory element \"prototype\".\n"
            + "Added directory element \"install\".\n"
            + "Added directory element \"service\".\n"
            + ".\n"
            + "create directory version\n"
            + "20001215.092522\n"
            + author2
            + "\n"
            + "/main/0\n"
            + "\n"
            + ".\n"
            + "create branch\n"
            + "20001215.092522\n"
            + author1
            + "\n"
            + "/main\n"
            + "\n"
            + ".\n"
            + "create directory element\n"
            + "20001215.092522\n"
            + author1
            + "\n"
            + "\n"
            + "\n"
            + ".";
    History result = instance.parse(output);
    assertNotNull(result);
    assertEquals(4, result.getHistoryEntries().size());

    HistoryEntry e1 = result.getHistoryEntries().get(0);
    assertEquals("/main/3", e1.getRevision());
    assertEquals(author1, e1.getAuthor());
    assertEquals(0, e1.getFiles().size());
    assertTrue(e1.getMessage().contains("prototype"));

    HistoryEntry e4 = result.getHistoryEntries().get(3);
    assertEquals("/main/0", e4.getRevision());
    assertEquals(author2, e4.getAuthor());
    assertEquals(0, e4.getFiles().size());
  }
    @Override
    protected JPanel processFiles(@NotNull List<Element> fileElements, final JPanel context) {
      final Ref<EditorWindow> windowRef = new Ref<EditorWindow>();
      UIUtil.invokeAndWaitIfNeeded(
          new Runnable() {
            @Override
            public void run() {
              windowRef.set(context == null ? createEditorWindow() : findWindowWith(context));
            }
          });
      final EditorWindow window = windowRef.get();
      LOG.assertTrue(window != null);
      VirtualFile focusedFile = null;

      for (int i = 0; i < fileElements.size(); i++) {
        final Element file = fileElements.get(i);
        if (i == 0) {
          EditorTabbedContainer tabbedPane = window.getTabbedPane();
          if (tabbedPane != null) {
            try {
              int limit =
                  Integer.parseInt(
                      file.getParentElement()
                          .getAttributeValue(
                              JBTabsImpl.SIDE_TABS_SIZE_LIMIT_KEY.toString(),
                              String.valueOf(JBTabsImpl.DEFAULT_MAX_TAB_WIDTH)));
              UIUtil.putClientProperty(
                  tabbedPane.getComponent(), JBTabsImpl.SIDE_TABS_SIZE_LIMIT_KEY, limit);
            } catch (NumberFormatException e) {
              // ignore
            }
          }
        }
        try {
          final FileEditorManagerImpl fileEditorManager = getManager();
          Element historyElement = file.getChild(HistoryEntry.TAG);
          final HistoryEntry entry =
              HistoryEntry.createLight(fileEditorManager.getProject(), historyElement);
          final VirtualFile virtualFile = entry.getFile();
          if (virtualFile == null)
            throw new InvalidDataException("No file exists: " + entry.getFilePointer().getUrl());
          Document document =
              ApplicationManager.getApplication()
                  .runReadAction(
                      new Computable<Document>() {
                        @Override
                        public Document compute() {
                          return virtualFile.isValid()
                              ? FileDocumentManager.getInstance().getDocument(virtualFile)
                              : null;
                        }
                      });
          final boolean isCurrentInTab =
              Boolean.valueOf(file.getAttributeValue(CURRENT_IN_TAB)).booleanValue();
          Boolean pin = Boolean.valueOf(file.getAttributeValue(PINNED));
          fileEditorManager.openFileImpl4(
              window, virtualFile, entry, isCurrentInTab, isCurrentInTab, pin, i);
          if (isCurrentInTab) {
            focusedFile = virtualFile;
          }
          if (document != null) {
            // This is just to make sure document reference is kept on stack till this point
            // so that document is available for folding state deserialization in HistoryEntry
            // constructor
            // and that document will be created only once during file opening
            document.putUserData(DUMMY_KEY, null);
          }
          updateProgress();
        } catch (InvalidDataException e) {
          if (ApplicationManager.getApplication().isUnitTestMode()) {
            LOG.error(e);
          }
        }
      }
      if (focusedFile != null) {
        getManager().addSelectionRecord(focusedFile, window);
      }
      return window.myPanel;
    }
  private void storeHistory(ConnectionResource conn, History history, Repository repository)
      throws SQLException {

    Integer reposId = null;
    Map<String, Integer> authors = null;
    Map<String, Integer> files = null;
    Map<String, Integer> directories = null;
    PreparedStatement addChangeset = null;
    PreparedStatement addDirchange = null;
    PreparedStatement addFilechange = null;
    PreparedStatement addFilemove = null;
    RuntimeEnvironment env = RuntimeEnvironment.getInstance();

    // return immediately when there is nothing to do
    List<HistoryEntry> entries = history.getHistoryEntries();
    if (entries.isEmpty()) {
      return;
    }

    for (int i = 0; ; i++) {
      try {
        if (reposId == null) {
          reposId = getRepositoryId(conn, repository);
          conn.commit();
        }

        if (authors == null) {
          authors = getAuthors(conn, history, reposId);
          conn.commit();
        }

        if (directories == null || files == null) {
          Map<String, Integer> dirs = new HashMap<String, Integer>();
          Map<String, Integer> fls = new HashMap<String, Integer>();
          getFilesAndDirectories(conn, history, reposId, dirs, fls);
          conn.commit();
          directories = dirs;
          files = fls;
        }

        if (addChangeset == null) {
          addChangeset = conn.getStatement(ADD_CHANGESET);
        }

        if (addDirchange == null) {
          addDirchange = conn.getStatement(ADD_DIRCHANGE);
        }

        if (addFilechange == null) {
          addFilechange = conn.getStatement(ADD_FILECHANGE);
        }

        if (addFilemove == null) {
          addFilemove = conn.getStatement(ADD_FILEMOVE);
        }

        // Success! Break out of the loop.
        break;

      } catch (SQLException sqle) {
        handleSQLException(sqle, i);
        conn.rollback();
      }
    }

    addChangeset.setInt(1, reposId);

    // getHistoryEntries() returns the entries in reverse chronological
    // order, but we want to insert them in chronological order so that
    // their auto-generated identity column can be used as a chronological
    // ordering column. Otherwise, incremental updates will make the
    // identity column unusable for chronological ordering. So therefore
    // we walk the list backwards.
    for (ListIterator<HistoryEntry> it = entries.listIterator(entries.size()); it.hasPrevious(); ) {
      HistoryEntry entry = it.previous();
      retry:
      for (int i = 0; ; i++) {
        try {
          addChangeset.setString(2, entry.getRevision());
          addChangeset.setInt(3, authors.get(entry.getAuthor()));
          addChangeset.setTimestamp(4, new Timestamp(entry.getDate().getTime()));
          String msg = entry.getMessage();
          // Truncate the message if it can't fit in a VARCHAR
          // (bug #11663).
          if (msg.length() > MAX_MESSAGE_LENGTH) {
            msg = truncate(msg, MAX_MESSAGE_LENGTH);
          }
          addChangeset.setString(5, msg);
          int changesetId = nextChangesetId.getAndIncrement();
          addChangeset.setInt(6, changesetId);
          addChangeset.executeUpdate();

          // Add one row for each file in FILECHANGES, and one row
          // for each path element of the directories in DIRCHANGES.
          Set<String> addedDirs = new HashSet<String>();
          addDirchange.setInt(1, changesetId);
          addFilechange.setInt(1, changesetId);
          for (String file : entry.getFiles()) {
            // ignore ignored files
            String repodir = "";
            try {
              repodir = env.getPathRelativeToSourceRoot(new File(repository.getDirectoryName()), 0);
            } catch (IOException ex) {
              Logger.getLogger(JDBCHistoryCache.class.getName()).log(Level.SEVERE, null, ex);
            }

            String fullPath = toUnixPath(file);
            if (!history.isIgnored(file.substring(repodir.length() + 1))) {
              int fileId = files.get(fullPath);
              addFilechange.setInt(2, fileId);
              addFilechange.executeUpdate();
            }
            String[] pathElts = splitPath(fullPath);
            for (int j = 0; j < pathElts.length; j++) {
              String dir = unsplitPath(pathElts, j);
              // Only add to DIRCHANGES if we haven't already
              // added this dir/changeset combination.
              if (!addedDirs.contains(dir)) {
                addDirchange.setInt(2, directories.get(dir));
                addDirchange.executeUpdate();
                addedDirs.add(dir);
              }
            }
          }

          conn.commit();

          // Successfully added the entry. Break out of retry loop.
          break retry;

        } catch (SQLException sqle) {
          handleSQLException(sqle, i);
          conn.rollback();
        }
      }
    }

    /*
     * Special handling for certain files - this is mainly for files which
     * have been renamed in Mercurial repository.
     * This ensures that their complete history (follow) will be saved.
     */
    for (String filename : history.getIgnoredFiles()) {
      String file_path = repository.getDirectoryName() + File.separatorChar + filename;
      File file = new File(file_path);
      String repo_path = file_path.substring(env.getSourceRootPath().length());
      History hist;
      try {
        hist = repository.getHistory(file);
      } catch (HistoryException ex) {
        Logger.getLogger(JDBCHistoryCache.class.getName()).log(Level.SEVERE, null, ex);
        continue;
      }

      int fileId = files.get(repo_path);
      for (HistoryEntry entry : hist.getHistoryEntries()) {
        retry:
        for (int i = 0; ; i++) {
          try {
            int changesetId = getIdForRevision(entry.getRevision());

            /*
             * If the file exists in the changeset, store it in
             * the table tracking moves of the file when it had
             * one of its precedent names so it can be found
             * when performing historyget on directory.
             */
            if (entry.getFiles().contains(repo_path)) {
              addFilechange.setInt(1, changesetId);
              addFilechange.setInt(2, fileId);
              addFilechange.executeUpdate();
            } else {
              addFilemove.setInt(1, changesetId);
              addFilemove.setInt(2, fileId);
              addFilemove.executeUpdate();
            }

            conn.commit();
            break retry;
          } catch (SQLException sqle) {
            handleSQLException(sqle, i);
            conn.rollback();
          }
        }
      }
    }
  }
  /** Test of parse method, of class ClearCaseHistoryParser. */
  @Test
  public void parseFileHistory() throws Exception {
    String author1 = "First Last (username)";
    String author2 = "First2 Last2 (username2)";
    String output =
        "create version\n"
            + "20020618.212343\n"
            + author1
            + "\n"
            + "/main/3\n"
            + "Merge from eeeee for ffffff\n"
            + ".\n"
            + "create version\n"
            + "20020222.164239\n"
            + author2
            + "\n"
            + "/main/2\n"
            + "Merge from projper branch.\n"
            + "Adding aaaaaaa to the yyyyy.\n"
            + ".\n"
            + "create version\n"
            + "20020208.150825\n"
            + author2
            + "\n"
            + "/main/1\n"
            + "Target for javac set to 1.3.\n"
            + "Fixed handling of "
            + " res directory.\n"
            + ".\n"
            + "create version\n"
            + "20010924.095104\n"
            + author2
            + "\n"
            + "/main/0\n"
            + "\n"
            + ".\n"
            + "create branch\n"
            + "20010924.095104\n"
            + author2
            + "\n"
            + "/main\n"
            + "\n"
            + ".\n"
            + "create file element\n"
            + "20010924.095104\n"
            + author1
            + "\n"
            + "\n"
            + "\n"
            + ".";

    History result = instance.parse(output);
    assertNotNull(result);
    assertEquals(4, result.getHistoryEntries().size());

    HistoryEntry e1 = result.getHistoryEntries().get(0);
    assertEquals("/main/3", e1.getRevision());
    assertEquals(author1, e1.getAuthor());
    assertEquals(0, e1.getFiles().size());
    assertTrue(e1.getMessage().contains("eeeee"));

    HistoryEntry e4 = result.getHistoryEntries().get(3);
    assertEquals("/main/0", e4.getRevision());
    assertEquals(author2, e4.getAuthor());
    assertEquals(0, e4.getFiles().size());
  }