Rename EiffelEventParser and EiffelEventParserIf
When an interface was extracted from EiffelEventParser in a previous
commit the implementing class kept the name EiffelEventParser to make
the diff more reviewable. In this change we rename the interface
`EiffelEventParser` and the implementation `EiffelEventParserImpl`
to align with the inofficial code-standard in Gerrit.
Solves: Jira GER-1715
Change-Id: I2ad5a139f0e6b983b615414450a9bc1a75a1128f
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java
index 9f53bee..9bdc0c4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java
@@ -40,7 +40,7 @@
import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventMapper;
import com.googlesource.gerrit.plugins.eventseiffel.mq.RabbitMqPublisher;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser;
-import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf;
+import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserImpl;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParsingExecutor;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParsingQueue;
import com.googlesource.gerrit.plugins.eventseiffel.rest.RestModule;
@@ -100,7 +100,7 @@
.in(Scopes.SINGLETON);
bind(EiffelEventParsingExecutor.Scheduled.class).in(Scopes.SINGLETON);
bind(EiffelEventParsingExecutor.class).to(EiffelEventParsingExecutor.Scheduled.class);
- bind(EiffelEventParserIf.class).to(EiffelEventParser.class);
+ bind(EiffelEventParser.class).to(EiffelEventParserImpl.class);
bind(EiffelEventParsingQueue.class).in(Scopes.SINGLETON);
bind(EiffelEventHubImpl.class).in(Scopes.SINGLETON);
bind(EiffelEventHub.class).to(EiffelEventHubImpl.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java
index df82291..6c0ad07 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Android Open Source Project
+// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,419 +11,64 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
package com.googlesource.gerrit.plugins.eventseiffel.parsing;
-import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType.SCC;
-
-import com.github.rholder.retry.RetryException;
-import com.github.rholder.retry.Retryer;
-import com.github.rholder.retry.RetryerBuilder;
-import com.github.rholder.retry.StopStrategies;
-import com.github.rholder.retry.WaitStrategies;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Project;
-import com.google.gerrit.entities.RefNames;
-import com.google.gerrit.exceptions.NoSuchEntityException;
import com.google.gerrit.extensions.common.AccountInfo;
-import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.events.RevisionCreatedListener.Event;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventHub;
-import com.googlesource.gerrit.plugins.eventseiffel.cache.EiffelEventIdLookupException;
-import com.googlesource.gerrit.plugins.eventseiffel.eiffel.CompositionDefinedEventKey;
-import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey;
-import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEvent;
-import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventMapper;
-import com.googlesource.gerrit.plugins.eventseiffel.parsing.UnprocessedCommitsWalker.EventCreate;
-import com.googlesource.gerrit.plugins.eventseiffel.parsing.UnprocessedCommitsWalker.ScsWalker;
-import java.io.IOException;
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-/** Creates and pushes missing Eiffel events to the Eiffel event queue. */
-public class EiffelEventParser implements EiffelEventParserIf {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+public interface EiffelEventParser {
- private static final int NBR_RETRIES = 3;
+ void createAndScheduleSccFromEvent(Event event);
- private final EiffelEventHub eventHub;
- private final GitRepositoryManager repoManager;
- private final UnprocessedCommitsWalker.Factory walkerFactory;
- private final EiffelEventMapper mapper;
-
- @Inject
- public EiffelEventParser(
- EiffelEventHub eventQueue,
- GitRepositoryManager repoManager,
- EiffelEventMapper mapper,
- UnprocessedCommitsWalker.Factory walkerFactory) {
- this.eventHub = eventQueue;
- this.repoManager = repoManager;
- this.walkerFactory = walkerFactory;
- this.mapper = mapper;
- }
-
- /* (non-Javadoc)
- * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf#createAndScheduleSccFromEvent(com.google.gerrit.extensions.events.RevisionCreatedListener.Event)
+ /**
+ * Creates SCC events for all commits reachable from branchRef. I.e. create SCCs for already
+ * merged commit that are missing SCCs.
+ *
+ * @param repoName
+ * @param branchRef
*/
- @Override
- public void createAndScheduleSccFromEvent(Event event) {
- CommitInfo commit = event.getRevision().commit;
- SourceChangeEventKey scc =
- SourceChangeEventKey.sccKey(
- event.getChange().project, event.getChange().branch, commit.commit);
- try {
- if (eventHub.getExistingId(scc).isPresent()) {
- logger.atWarning().log(
- "Event %s already pushed for %d/%d",
- scc, event.getChange()._number, event.getRevision()._number);
- return;
- }
- List<UUID> parentUuids = Lists.newArrayList();
- for (CommitInfo parent : commit.parents) {
- Optional<UUID> parentUuid = eventHub.getExistingId(scc.copy(parent.commit));
- if (parentUuid.isPresent()) {
- parentUuids.add(parentUuid.get());
- }
- }
+ void createAndScheduleSccFromBranch(String repoName, String branchRef);
- /* Eiffel events have been scheduled or published for all parents. */
- if (parentUuids.size() == commit.parents.size()) {
- pushToHub(mapper.toScc(event, parentUuids));
- } else {
- createAndScheduleMissingSccs(scc);
- }
- } catch (IOException
- | ConfigInvalidException
- | NoSuchEntityException
- | EiffelEventIdLookupException
- | InterruptedException e) {
- logger.atSevere().withCause(e).log(
- "Event creation failed for: %s, %s, %s to SCC.",
- event.getChange().project, event.getChange().branch, event.getRevision().commit.commit);
- }
- }
-
- /* (non-Javadoc)
- * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf#createAndScheduleSccFromBranch(java.lang.String, java.lang.String)
+ /**
+ * Creates SCC events for all commits reachable from commit.
+ *
+ * @param repoName
+ * @param targetBranch
+ * @param commit
*/
- @Override
- public void createAndScheduleSccFromBranch(String repoName, String branchRef) {
- ObjectId tip = getTipOf(repoName, branchRef);
- if (tip == null) {
- return;
- }
- createAndScheduleSccFromCommit(repoName, branchRef, tip.getName());
- }
+ void createAndScheduleSccFromCommit(String repoName, String targetBranch, String commit);
- /* (non-Javadoc)
- * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf#createAndScheduleSccFromCommit(java.lang.String, java.lang.String, java.lang.String)
+ /**
+ * Creates missing SCS events for repoName, branch.
+ *
+ * @param repoName
+ * @param branch
*/
- @Override
- public void createAndScheduleSccFromCommit(String repoName, String branchRef, String commit) {
+ void createAndScheduleMissingScssFromBranch(String repoName, String branch);
- SourceChangeEventKey scc = SourceChangeEventKey.sccKey(repoName, branchRef, commit);
- try {
- createAndScheduleMissingSccs(scc);
- } catch (IOException
- | EiffelEventIdLookupException
- | NoSuchEntityException
- | ConfigInvalidException
- | InterruptedException e) {
- logger.atSevere().withCause(e).log("Event creation failed for: %s", scc);
- }
- }
-
- /* (non-Javadoc)
- * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf#createAndScheduleMissingScssFromBranch(java.lang.String, java.lang.String)
+ /**
+ * Creates missing SCS events for a submit transaction. submitter and submittedAt is set for all
+ * events created within the submit transaction, i.e. not reachable from commitSha1TransactionEnd.
+ *
+ * @param scs
+ * @param commitSha1TransactionEnd
+ * @param submitter
+ * @param submittedAt
*/
- @Override
- public void createAndScheduleMissingScssFromBranch(String repoName, String branchRef) {
- ObjectId tip = getTipOf(repoName, branchRef);
- if (tip == null) {
- return;
- }
- SourceChangeEventKey scs = SourceChangeEventKey.scsKey(repoName, branchRef, tip.getName());
- createAndScheduleMissingScss(scs, null, null, null);
- }
-
- /* (non-Javadoc)
- * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf#createAndScheduleMissingScss(com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey, java.lang.String, com.google.gerrit.extensions.common.AccountInfo, java.lang.Long)
- */
- @Override
- public void createAndScheduleMissingScss(
+ void createAndScheduleMissingScss(
SourceChangeEventKey scs,
String commitSha1TransactionEnd,
AccountInfo submitter,
- Long submittedAt) {
- SourceChangeEventKey currentScs = scs;
- SourceChangeEventKey scc = scs.copy(SCC);
- try {
- try (ScsWalker scsFinder =
- walkerFactory.scsWalker(scs, commitSha1TransactionEnd, submitter, submittedAt)) {
+ Long submittedAt);
- if (eventHub.getExistingId(scc).isEmpty()) {
- /* One or several SCC events are missing, create them first */
- try (UnprocessedCommitsWalker sccFinder = scsFinder.sccWalker()) {
- createAndScheduleMissingSccs(scc, sccFinder);
- }
- }
-
- if (!scsFinder.hasNext()) {
- logger.atInfo().log("All events were already published for %s", scs);
- } else {
- logger.atFine().log("Start publishing events for: %s", scs);
- }
- while (scsFinder.hasNext()) {
- EventCreate create = scsFinder.next();
- currentScs = create.key;
- Optional<UUID> sccId = eventHub.getExistingId(create.key.copy(SCC));
- if (sccId.isEmpty()) {
- throw new EiffelEventIdLookupException(
- "Unable to find SCC event id: %s", create.key.copy(SCC));
- }
- List<UUID> scsParentEventIds = Lists.newArrayList();
- for (RevCommit parent : create.commit.getParents()) {
- Optional<UUID> parentUuid = eventHub.getExistingId(create.key.copy(parent.getName()));
- if (parentUuid.isPresent()) {
- scsParentEventIds.add(parentUuid.get());
- } else {
- exceptionForMissingParent(create, parent);
- }
- }
- pushToHub(
- mapper.toScs(
- create.commit,
- create.key.repo(),
- create.key.branch(),
- create.submitter,
- create.submittedAt,
- scsParentEventIds,
- sccId.get()));
- }
- }
- logger.atFine().log("Done publishing events for: %s", scs);
- } catch (IOException
- | EiffelEventIdLookupException
- | InterruptedException
- | ConfigInvalidException
- | NoSuchEntityException e) {
- logger.atSevere().withCause(e).log("Failed to create Eiffel event(s) for %s.", currentScs);
- }
- }
-
- /* (non-Javadoc)
- * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf#createAndScheduleArtc(java.lang.String, java.lang.String, java.lang.Long, boolean)
+ /**
+ * Creates missing ARTC for a tag, together with CD and (if missing) SCS for referenced commit.7
+ *
+ * @param projectName
+ * @param tagName
+ * @param creationTime
+ * @param force
*/
- @Override
- public void createAndScheduleArtc(
- String repoName, String tagName, Long creationTime, boolean force) {
- try {
- CompositionDefinedEventKey cd =
- CompositionDefinedEventKey.create(mapper.tagCompositionName(repoName), tagName);
- Optional<UUID> oldCdId = eventHub.getExistingId(cd);
- if (oldCdId.isEmpty() || force) {
- createAndScheduleCd(repoName, tagName, creationTime, force);
- Optional<UUID> cdId = eventHub.getExistingId(cd);
- if (cdId.isPresent() && !cdId.equals(oldCdId)) {
- pushToHub(mapper.toArtc(repoName, tagName, creationTime, cdId.get()), force);
- if (oldCdId.isPresent()) {
- logger.atInfo().log(
- "Event Artc has been forcibly created for: %s, %s", repoName, tagName);
- } else {
- logger.atFine().log("Event Artc has been created for: %s, %s", repoName, tagName);
- }
- }
- } else {
- /* Artc event has already been created */
- logger.atWarning().log(
- "Event Artc has already been created for: %s, %s", repoName, tagName);
- }
- } catch (EiffelEventIdLookupException | InterruptedException e) {
- logger.atSevere().withCause(e).log(
- "Event creation failed for: %s, %s to Artc", repoName, tagName);
- }
- }
-
- private void createAndScheduleCd(
- String projectName, String tagName, Long creationTime, boolean force) {
- SourceChangeEventKey scs = null;
- Optional<UUID> scsId = Optional.empty();
-
- try {
- String commitId = peelTag(projectName, tagName);
- if (commitId == null) {
- return;
- }
- scs = SourceChangeEventKey.scsKey(projectName, RefNames.REFS_HEADS + "master", commitId);
- scsId = eventHub.getExistingId(scs);
-
- if (scsId.isEmpty()) {
- Retryer<Optional<UUID>> retryer =
- RetryerBuilder.<Optional<UUID>>newBuilder()
- .retryIfResult(Optional::isEmpty)
- .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
- .withStopStrategy(StopStrategies.stopAfterAttempt(2))
- .build();
- try {
- scsId = retryer.call(() -> findSourceChangeEventKey(projectName, commitId));
- } catch (RetryException | ExecutionException e) {
- logger.atSevere().withCause(e).log(
- "Failed to find SCS for %s in %s", commitId, projectName);
- return;
- }
- }
- if (scsId.isEmpty()) {
- logger.atSevere().log("Could not find SCS for: %s in %s", commitId, projectName);
- return;
- }
- pushToHub(mapper.toCd(projectName, tagName, creationTime, scsId.get()), force);
- } catch (EiffelEventIdLookupException | InterruptedException e) {
- logger.atSevere().withCause(e).log(
- "Event creation failed for: %s",
- CompositionDefinedEventKey.create(mapper.tagCompositionName(projectName), tagName));
- }
- }
-
- private String peelTag(String projectName, String tagName) {
- try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
- Ref tagRef = repo.getRefDatabase().exactRef(Constants.R_TAGS + tagName);
- if (tagRef != null) {
- ObjectId peeled = repo.getRefDatabase().peel(tagRef).getPeeledObjectId();
- return peeled != null ? peeled.getName() : tagRef.getObjectId().getName();
- }
- logger.atSevere().log("Cannot find tag: %s:%s", projectName, tagName);
- } catch (IOException e) {
- logger.atSevere().withCause(e).log("Unable to peel tag: %s:%s", projectName, tagName);
- }
- return null;
- }
-
- private Optional<UUID> findSourceChangeEventKey(String projectName, String commitId)
- throws EiffelEventIdLookupException {
- List<String> branches;
- try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
- branches =
- repo.getRefDatabase().getRefsByPrefix(RefNames.REFS_HEADS).stream()
- .map(Ref::getName)
- .collect(Collectors.toList());
- } catch (IOException ioe) {
- logger.atSevere().withCause(ioe).log("Unable to find branches of %s.", projectName);
- return Optional.empty();
- }
- return eventHub.getScsForCommit(projectName, commitId, branches);
- }
-
- private void pushToHub(EiffelEvent toPush) throws InterruptedException {
- pushToHub(toPush, false);
- }
-
- private void pushToHub(EiffelEvent toPush, boolean force) throws InterruptedException {
- int failureCount = 0;
- EventKey key = EventKey.fromEvent(toPush);
- while (true) {
- try {
- eventHub.push(toPush, force);
- logger.atFine().log("Successfully pushed %s to EventHub", key);
- return;
- } catch (InterruptedException e) {
- if (!eventHub.isOpen()) {
- logger.atInfo().log("EventHub is closed, aborting.");
- throw e;
- }
- failureCount++;
- if (failureCount < NBR_RETRIES) {
- logger.atWarning().withCause(e).log(
- "Interrupted while pushing %s to EventHub, attempt %d/%d",
- key, failureCount, NBR_RETRIES);
- } else {
- throw e;
- }
- }
- }
- }
-
- @VisibleForTesting
- void createAndScheduleMissingSccs(SourceChangeEventKey scc)
- throws MissingObjectException, IncorrectObjectTypeException, IOException,
- EiffelEventIdLookupException, RepositoryNotFoundException, NoSuchEntityException,
- ConfigInvalidException, InterruptedException {
- logger.atFine().log("Start publishing events for: %s", scc);
- try (UnprocessedCommitsWalker commitFinder = walkerFactory.sccWalker(scc)) {
- createAndScheduleMissingSccs(scc, commitFinder);
- }
- logger.atFine().log("Done publishing events for: %s", scc);
- }
-
- /* Callers are responsible for closing commitFinder. */
- private void createAndScheduleMissingSccs(
- SourceChangeEventKey scc, UnprocessedCommitsWalker commitFinder)
- throws MissingObjectException, EiffelEventIdLookupException, IOException,
- NoSuchEntityException, ConfigInvalidException, InterruptedException {
- if (!commitFinder.hasNext()) {
- logger.atInfo().log("All events were already published for %s", scc);
- } else {
- logger.atFine().log("Start publishing events for: %s", scc);
- }
- while (commitFinder.hasNext()) {
- EventCreate job = commitFinder.next();
- logger.atFine().log("Processing event-creation for: %s", job.key);
- List<UUID> parentIds = Lists.newArrayList();
- for (RevCommit parent : job.commit.getParents()) {
- SourceChangeEventKey parentKey = scc.copy(parent.getName());
- Optional<UUID> parentId = eventHub.getExistingId(parentKey);
- if (parentId.isPresent()) {
- parentIds.add(parentId.get());
- } else {
- exceptionForMissingParent(job, parent);
- }
- }
- try {
- pushToHub(mapper.toScc(job.commit, job.key.repo(), job.key.branch(), parentIds));
- } catch (InterruptedException e) {
- logger.atSevere().log("Interrupted while pushing %s to EventHub.", job.key);
- throw e;
- }
- }
- }
-
- private ObjectId getTipOf(String repoName, String branch) {
- try (Repository repo = repoManager.openRepository(Project.nameKey(repoName))) {
- Ref branchRef = repo.exactRef(branch);
- if (branchRef == null) {
- logger.atWarning().log("Could not find ref: %s in project: %s", branch, repoName);
- return null;
- }
- return branchRef.getTarget().getObjectId();
- } catch (IOException ioe) {
- logger.atSevere().withCause(ioe).log("Unable to identify tip of (%s:%s).", repoName, branch);
- return null;
- }
- }
-
- private void exceptionForMissingParent(EventCreate create, RevCommit parent)
- throws NoSuchEntityException {
- throw new NoSuchEntityException(
- String.format(
- "Unable to lookup parent (%s) event UUID for %s even though it should exist.",
- parent.abbreviate(7).name(), create.key));
- }
+ void createAndScheduleArtc(String projectName, String tagName, Long creationTime, boolean force);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIf.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIf.java
deleted file mode 100644
index 94aa921..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIf.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.googlesource.gerrit.plugins.eventseiffel.parsing;
-
-import com.google.gerrit.extensions.common.AccountInfo;
-import com.google.gerrit.extensions.events.RevisionCreatedListener.Event;
-import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey;
-
-public interface EiffelEventParserIf {
-
- void createAndScheduleSccFromEvent(Event event);
-
- /**
- * Creates SCC events for all commits reachable from branchRef. I.e. create SCCs for already
- * merged commit that are missing SCCs.
- *
- * @param repoName - Name of the repository where the branch exists.
- * @param branchRef - Creates missing events for all commits reachable from branch.
- */
- void createAndScheduleSccFromBranch(String repoName, String branchRef);
-
- /**
- * Creates SCC events for all commits reachable from commit.
- *
- * @param repoName - Name of the repository were the commits exists.
- * @param branchRef - Ref of the branch to create events for.
- * @param commit - Creates missing events for all commits reachable from commit.
- */
- void createAndScheduleSccFromCommit(String repoName, String branchRef, String commit);
-
- /**
- * Creates missing SCS events for repoName, branch.
- *
- * @param repoName - Name of the repository where the branch exists.
- * @param branchRef - Creates missing events for all commits reachable from branchRef.
- */
- void createAndScheduleMissingScssFromBranch(String repoName, String branchRef);
-
- /**
- * Creates missing SCS events for a submit transaction. submitter and submittedAt is set for all
- * events created within the submit transaction, i.e. not reachable from commitSha1TransactionEnd.
- *
- * @param scs - key for the event that shuold be created, together with parents.
- * @param commitSha1TransactionEnd - tip before submit transaction.
- * @param submitter - The submitter
- * @param submittedAt - When the commit was submitted.
- */
- void createAndScheduleMissingScss(
- SourceChangeEventKey scs,
- String commitSha1TransactionEnd,
- AccountInfo submitter,
- Long submittedAt);
-
- /**
- * Creates missing ARTC for a tag, together with CD and (if missing) SCS for referenced commit.
- *
- * @param repoName - Name of the repository were the tag exists.
- * @param tagName - The name of the tag.
- * @param creationTime - The time at which the tag was created.
- * @param force - Whether existing events should be replaced or not.
- */
- void createAndScheduleArtc(String repoName, String tagName, Long creationTime, boolean force);
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserImpl.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserImpl.java
new file mode 100644
index 0000000..5d54053
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserImpl.java
@@ -0,0 +1,429 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.eventseiffel.parsing;
+
+import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType.SCC;
+
+import com.github.rholder.retry.RetryException;
+import com.github.rholder.retry.Retryer;
+import com.github.rholder.retry.RetryerBuilder;
+import com.github.rholder.retry.StopStrategies;
+import com.github.rholder.retry.WaitStrategies;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.exceptions.NoSuchEntityException;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.CommitInfo;
+import com.google.gerrit.extensions.events.RevisionCreatedListener.Event;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventHub;
+import com.googlesource.gerrit.plugins.eventseiffel.cache.EiffelEventIdLookupException;
+import com.googlesource.gerrit.plugins.eventseiffel.eiffel.CompositionDefinedEventKey;
+import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey;
+import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey;
+import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEvent;
+import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventMapper;
+import com.googlesource.gerrit.plugins.eventseiffel.parsing.UnprocessedCommitsWalker.EventCreate;
+import com.googlesource.gerrit.plugins.eventseiffel.parsing.UnprocessedCommitsWalker.ScsWalker;
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+/** Creates and pushes missing Eiffel events to the Eiffel event queue. */
+public class EiffelEventParserImpl implements EiffelEventParser {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private static final int NBR_RETRIES = 3;
+
+ private final EiffelEventHub eventHub;
+ private final GitRepositoryManager repoManager;
+ private final UnprocessedCommitsWalker.Factory walkerFactory;
+ private final EiffelEventMapper mapper;
+
+ @Inject
+ public EiffelEventParserImpl(
+ EiffelEventHub eventQueue,
+ GitRepositoryManager repoManager,
+ EiffelEventMapper mapper,
+ UnprocessedCommitsWalker.Factory walkerFactory) {
+ this.eventHub = eventQueue;
+ this.repoManager = repoManager;
+ this.walkerFactory = walkerFactory;
+ this.mapper = mapper;
+ }
+
+ /* (non-Javadoc)
+ * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser#createAndScheduleSccFromEvent(com.google.gerrit.extensions.events.RevisionCreatedListener.Event)
+ */
+ @Override
+ public void createAndScheduleSccFromEvent(Event event) {
+ CommitInfo commit = event.getRevision().commit;
+ SourceChangeEventKey scc =
+ SourceChangeEventKey.sccKey(
+ event.getChange().project, event.getChange().branch, commit.commit);
+ try {
+ if (eventHub.getExistingId(scc).isPresent()) {
+ logger.atWarning().log(
+ "Event %s already pushed for %d/%d",
+ scc, event.getChange()._number, event.getRevision()._number);
+ return;
+ }
+ List<UUID> parentUuids = Lists.newArrayList();
+ for (CommitInfo parent : commit.parents) {
+ Optional<UUID> parentUuid = eventHub.getExistingId(scc.copy(parent.commit));
+ if (parentUuid.isPresent()) {
+ parentUuids.add(parentUuid.get());
+ }
+ }
+
+ /* Eiffel events have been scheduled or published for all parents. */
+ if (parentUuids.size() == commit.parents.size()) {
+ pushToHub(mapper.toScc(event, parentUuids));
+ } else {
+ createAndScheduleMissingSccs(scc);
+ }
+ } catch (IOException
+ | ConfigInvalidException
+ | NoSuchEntityException
+ | EiffelEventIdLookupException
+ | InterruptedException e) {
+ logger.atSevere().withCause(e).log(
+ "Event creation failed for: %s, %s, %s to SCC.",
+ event.getChange().project, event.getChange().branch, event.getRevision().commit.commit);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser#createAndScheduleSccFromBranch(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void createAndScheduleSccFromBranch(String repoName, String targetBranch) {
+ ObjectId tip = getTipOf(repoName, targetBranch);
+ if (tip == null) {
+ return;
+ }
+ createAndScheduleSccFromCommit(repoName, targetBranch, tip.getName());
+ }
+
+ /* (non-Javadoc)
+ * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser#createAndScheduleSccFromCommit(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void createAndScheduleSccFromCommit(String repoName, String targetBranch, String commit) {
+
+ SourceChangeEventKey scc = SourceChangeEventKey.sccKey(repoName, targetBranch, commit);
+ try {
+ createAndScheduleMissingSccs(scc);
+ } catch (IOException
+ | EiffelEventIdLookupException
+ | NoSuchEntityException
+ | ConfigInvalidException
+ | InterruptedException e) {
+ logger.atSevere().withCause(e).log("Event creation failed for: %s", scc);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser#createAndScheduleMissingScssFromBranch(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void createAndScheduleMissingScssFromBranch(String repoName, String branch) {
+ ObjectId tip = getTipOf(repoName, branch);
+ if (tip == null) {
+ return;
+ }
+ SourceChangeEventKey scs = SourceChangeEventKey.scsKey(repoName, branch, tip.getName());
+ createAndScheduleMissingScss(scs, null, null, null);
+ }
+
+ /* (non-Javadoc)
+ * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser#createAndScheduleMissingScss(com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey, java.lang.String, com.google.gerrit.extensions.common.AccountInfo, java.lang.Long)
+ */
+ @Override
+ public void createAndScheduleMissingScss(
+ SourceChangeEventKey scs,
+ String commitSha1TransactionEnd,
+ AccountInfo submitter,
+ Long submittedAt) {
+ SourceChangeEventKey currentScs = scs;
+ SourceChangeEventKey scc = scs.copy(SCC);
+ try {
+ try (ScsWalker scsFinder =
+ walkerFactory.scsWalker(scs, commitSha1TransactionEnd, submitter, submittedAt)) {
+
+ if (eventHub.getExistingId(scc).isEmpty()) {
+ /* One or several SCC events are missing, create them first */
+ try (UnprocessedCommitsWalker sccFinder = scsFinder.sccWalker()) {
+ createAndScheduleMissingSccs(scc, sccFinder);
+ }
+ }
+
+ if (!scsFinder.hasNext()) {
+ logger.atInfo().log("All events were already published for %s", scs);
+ } else {
+ logger.atFine().log("Start publishing events for: %s", scs);
+ }
+ while (scsFinder.hasNext()) {
+ EventCreate create = scsFinder.next();
+ currentScs = create.key;
+ Optional<UUID> sccId = eventHub.getExistingId(create.key.copy(SCC));
+ if (sccId.isEmpty()) {
+ throw new EiffelEventIdLookupException(
+ "Unable to find SCC event id: %s", create.key.copy(SCC));
+ }
+ List<UUID> scsParentEventIds = Lists.newArrayList();
+ for (RevCommit parent : create.commit.getParents()) {
+ Optional<UUID> parentUuid = eventHub.getExistingId(create.key.copy(parent.getName()));
+ if (parentUuid.isPresent()) {
+ scsParentEventIds.add(parentUuid.get());
+ } else {
+ exceptionForMissingParent(create, parent);
+ }
+ }
+ pushToHub(
+ mapper.toScs(
+ create.commit,
+ create.key.repo(),
+ create.key.branch(),
+ create.submitter,
+ create.submittedAt,
+ scsParentEventIds,
+ sccId.get()));
+ }
+ }
+ logger.atFine().log("Done publishing events for: %s", scs);
+ } catch (IOException
+ | EiffelEventIdLookupException
+ | InterruptedException
+ | ConfigInvalidException
+ | NoSuchEntityException e) {
+ logger.atSevere().withCause(e).log("Failed to create Eiffel event(s) for %s.", currentScs);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser#createAndScheduleArtc(java.lang.String, java.lang.String, java.lang.Long, boolean)
+ */
+ @Override
+ public void createAndScheduleArtc(
+ String projectName, String tagName, Long creationTime, boolean force) {
+ try {
+ CompositionDefinedEventKey cd =
+ CompositionDefinedEventKey.create(mapper.tagCompositionName(projectName), tagName);
+ Optional<UUID> oldCdId = eventHub.getExistingId(cd);
+ if (oldCdId.isEmpty() || force) {
+ createAndScheduleCd(projectName, tagName, creationTime, force);
+ Optional<UUID> cdId = eventHub.getExistingId(cd);
+ if (cdId.isPresent() && !cdId.equals(oldCdId)) {
+ pushToHub(mapper.toArtc(projectName, tagName, creationTime, cdId.get()), force);
+ if (oldCdId.isPresent()) {
+ logger.atInfo().log(
+ "Event Artc has been forcibly created for: %s, %s", projectName, tagName);
+ } else {
+ logger.atFine().log("Event Artc has been created for: %s, %s", projectName, tagName);
+ }
+ }
+ } else {
+ /* Artc event has already been created */
+ logger.atWarning().log(
+ "Event Artc has already been created for: %s, %s", projectName, tagName);
+ }
+ } catch (EiffelEventIdLookupException | InterruptedException e) {
+ logger.atSevere().withCause(e).log(
+ "Event creation failed for: %s, %s to Artc", projectName, tagName);
+ }
+ }
+
+ private void createAndScheduleCd(
+ String projectName, String tagName, Long creationTime, boolean force) {
+ SourceChangeEventKey scs = null;
+ Optional<UUID> scsId = Optional.empty();
+
+ try {
+ String commitId = peelTag(projectName, tagName);
+ if (commitId == null) {
+ return;
+ }
+ scs = SourceChangeEventKey.scsKey(projectName, RefNames.REFS_HEADS + "master", commitId);
+ scsId = eventHub.getExistingId(scs);
+
+ if (scsId.isEmpty()) {
+ Retryer<Optional<UUID>> retryer =
+ RetryerBuilder.<Optional<UUID>>newBuilder()
+ .retryIfResult(Optional::isEmpty)
+ .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
+ .withStopStrategy(StopStrategies.stopAfterAttempt(2))
+ .build();
+ try {
+ scsId = retryer.call(() -> findSourceChangeEventKey(projectName, commitId));
+ } catch (RetryException | ExecutionException e) {
+ logger.atSevere().withCause(e).log(
+ "Failed to find SCS for %s in %s", commitId, projectName);
+ return;
+ }
+ }
+ if (scsId.isEmpty()) {
+ logger.atSevere().log("Could not find SCS for: %s in %s", commitId, projectName);
+ return;
+ }
+ pushToHub(mapper.toCd(projectName, tagName, creationTime, scsId.get()), force);
+ } catch (EiffelEventIdLookupException | InterruptedException e) {
+ logger.atSevere().withCause(e).log(
+ "Event creation failed for: %s",
+ CompositionDefinedEventKey.create(mapper.tagCompositionName(projectName), tagName));
+ }
+ }
+
+ private String peelTag(String projectName, String tagName) {
+ try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
+ Ref tagRef = repo.getRefDatabase().exactRef(Constants.R_TAGS + tagName);
+ if (tagRef != null) {
+ ObjectId peeled = repo.getRefDatabase().peel(tagRef).getPeeledObjectId();
+ return peeled != null ? peeled.getName() : tagRef.getObjectId().getName();
+ }
+ logger.atSevere().log("Cannot find tag: %s:%s", projectName, tagName);
+ } catch (IOException e) {
+ logger.atSevere().withCause(e).log("Unable to peel tag: %s:%s", projectName, tagName);
+ }
+ return null;
+ }
+
+ private Optional<UUID> findSourceChangeEventKey(String projectName, String commitId)
+ throws EiffelEventIdLookupException {
+ List<String> branches;
+ try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
+ branches =
+ repo.getRefDatabase().getRefsByPrefix(RefNames.REFS_HEADS).stream()
+ .map(Ref::getName)
+ .collect(Collectors.toList());
+ } catch (IOException ioe) {
+ logger.atSevere().withCause(ioe).log("Unable to find branches of %s.", projectName);
+ return Optional.empty();
+ }
+ return eventHub.getScsForCommit(projectName, commitId, branches);
+ }
+
+ private void pushToHub(EiffelEvent toPush) throws InterruptedException {
+ pushToHub(toPush, false);
+ }
+
+ private void pushToHub(EiffelEvent toPush, boolean force) throws InterruptedException {
+ int failureCount = 0;
+ EventKey key = EventKey.fromEvent(toPush);
+ while (true) {
+ try {
+ eventHub.push(toPush, force);
+ logger.atFine().log("Successfully pushed %s to EventHub", key);
+ return;
+ } catch (InterruptedException e) {
+ if (!eventHub.isOpen()) {
+ logger.atInfo().log("EventHub is closed, aborting.");
+ throw e;
+ }
+ failureCount++;
+ if (failureCount < NBR_RETRIES) {
+ logger.atWarning().withCause(e).log(
+ "Interrupted while pushing %s to EventHub, attempt %d/%d",
+ key, failureCount, NBR_RETRIES);
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void createAndScheduleMissingSccs(SourceChangeEventKey scc)
+ throws MissingObjectException, IncorrectObjectTypeException, IOException,
+ EiffelEventIdLookupException, RepositoryNotFoundException, NoSuchEntityException,
+ ConfigInvalidException, InterruptedException {
+ logger.atFine().log("Start publishing events for: %s", scc);
+ try (UnprocessedCommitsWalker commitFinder = walkerFactory.sccWalker(scc)) {
+ createAndScheduleMissingSccs(scc, commitFinder);
+ }
+ logger.atFine().log("Done publishing events for: %s", scc);
+ }
+
+ /* Callers are responsible for closing commitFinder. */
+ private void createAndScheduleMissingSccs(
+ SourceChangeEventKey scc, UnprocessedCommitsWalker commitFinder)
+ throws MissingObjectException, EiffelEventIdLookupException, IOException,
+ NoSuchEntityException, ConfigInvalidException, InterruptedException {
+ if (!commitFinder.hasNext()) {
+ logger.atInfo().log("All events were already published for %s", scc);
+ } else {
+ logger.atFine().log("Start publishing events for: %s", scc);
+ }
+ while (commitFinder.hasNext()) {
+ EventCreate job = commitFinder.next();
+ logger.atFine().log("Processing event-creation for: %s", job.key);
+ List<UUID> parentIds = Lists.newArrayList();
+ for (RevCommit parent : job.commit.getParents()) {
+ SourceChangeEventKey parentKey = scc.copy(parent.getName());
+ Optional<UUID> parentId = eventHub.getExistingId(parentKey);
+ if (parentId.isPresent()) {
+ parentIds.add(parentId.get());
+ } else {
+ exceptionForMissingParent(job, parent);
+ }
+ }
+ try {
+ pushToHub(mapper.toScc(job.commit, job.key.repo(), job.key.branch(), parentIds));
+ } catch (InterruptedException e) {
+ logger.atSevere().log("Interrupted while pushing %s to EventHub.", job.key);
+ throw e;
+ }
+ }
+ }
+
+ private ObjectId getTipOf(String repoName, String branch) {
+ try (Repository repo = repoManager.openRepository(Project.nameKey(repoName))) {
+ Ref branchRef = repo.exactRef(branch);
+ if (branchRef == null) {
+ logger.atWarning().log("Could not find ref: %s in project: %s", branch, repoName);
+ return null;
+ }
+ return branchRef.getTarget().getObjectId();
+ } catch (IOException ioe) {
+ logger.atSevere().withCause(ioe).log("Unable to identify tip of (%s:%s).", repoName, branch);
+ return null;
+ }
+ }
+
+ private void exceptionForMissingParent(EventCreate create, RevCommit parent)
+ throws NoSuchEntityException {
+ throw new NoSuchEntityException(
+ String.format(
+ "Unable to lookup parent (%s) event UUID for %s even though it should exist.",
+ parent.abbreviate(7).name(), create.key));
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java
index b457b6f..c5d10b8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java
@@ -36,12 +36,12 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private volatile EiffelEventParsingExecutor pool;
- private final EiffelEventParserIf eventParser;
+ private final EiffelEventParser eventParser;
private final ConcurrentHashMap<EventParsingWorker, ScheduledFuture<?>> pending =
new ConcurrentHashMap<>();
@Inject
- public EiffelEventParsingQueue(EiffelEventParsingExecutor pool, EiffelEventParserIf eventParser) {
+ public EiffelEventParsingQueue(EiffelEventParsingExecutor pool, EiffelEventParser eventParser) {
this.pool = pool;
this.eventParser = eventParser;
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java
index 579f3b6..17b5acd 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java
@@ -26,7 +26,7 @@
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.api.EventStorage;
import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventFactory;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser;
-import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserIf;
+import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParserImpl;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParsingExecutor;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParsingQueue;
import org.junit.Ignore;
@@ -44,7 +44,7 @@
bind(EiffelEventParsingExecutor.class).to(EiffelEventParsingExecutor.Direct.class);
bind(TestEventPublisher.class).in(Scopes.SINGLETON);
bind(EiffelEventHub.Consumer.class).to(TestEventPublisher.class);
- bind(EiffelEventParserIf.class).to(EiffelEventParser.class);
+ bind(EiffelEventParser.class).to(EiffelEventParserImpl.class);
bind(EiffelEventParsingQueue.class);
bind(EiffelEventFactory.class).toProvider(TestEventFactoryProvider.class);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
index d2d87eb..d20034b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
@@ -57,11 +57,11 @@
public class EiffelEventParserIT extends EiffelEventsTest {
private static final Long EPOCH_MILLIS = 978307261000l;
- private EiffelEventParser eventParser;
+ private EiffelEventParserImpl eventParser;
@Before
public void setUp() {
- eventParser = plugin.getSysInjector().getInstance(EiffelEventParser.class);
+ eventParser = plugin.getSysInjector().getInstance(EiffelEventParserImpl.class);
TestEventHub.EVENTS.clear();
}
@@ -342,7 +342,7 @@
bind(EiffelEventHub.class).to(TestEventHub.class);
bind(EventMappingConfig.class).toProvider(EventMappingConfig.Provider.class);
bind(EiffelEventMapper.class);
- bind(EiffelEventParserIf.class).to(EiffelEventParser.class);
+ bind(EiffelEventParser.class).to(EiffelEventParserImpl.class);
bind(EiffelConfig.class).toProvider(EiffelConfig.Provider.class).in(Scopes.SINGLETON);
bind(EiffelEventFactory.class)
.toProvider(EiffelEventFactory.Provider.class)