Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
use hibernate entity listener to capture translation update and broad…
Browse files Browse the repository at this point in the history
…case events
  • Loading branch information
Patrick Huang committed Jan 29, 2014
1 parent 2dbb248 commit 8582b85
Show file tree
Hide file tree
Showing 10 changed files with 335 additions and 19 deletions.
@@ -0,0 +1,24 @@
package org.zanata.events;

import org.zanata.common.LocaleId;
import org.zanata.webtrans.shared.auth.EditorClientId;
import org.zanata.webtrans.shared.model.TransUnitId;
import org.zanata.webtrans.shared.rpc.TransUnitUpdated;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
* @author Patrick Huang
* <a href="mailto:pahuang@redhat.com">pahuang@redhat.com</a>
*/
@RequiredArgsConstructor
@Getter
public class TextFlowTargetUpdateContextEvent {
public static final String EVENT_NAME = "org.zanata.event.TextFlowTargetUpdateContextEvent";

private final TransUnitId transUnitId;
private final LocaleId localeId;
private final EditorClientId editorClientId;
private final TransUnitUpdated.UpdateType updateType;
}
@@ -0,0 +1,52 @@
package org.zanata.webtrans.server;

import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.jboss.seam.Component;
import lombok.extern.slf4j.Slf4j;

/**
* @author Patrick Huang <a
* href="mailto:pahuang@redhat.com">pahuang@redhat.com</a>
*/
@Slf4j
public class HibernateIntegrator implements Integrator {
@Override
public void integrate(Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// As you might expect, an EventListenerRegistry is the thing with which
// event listeners are registered It is a
// service so we look it up using the service registry

final EventListenerRegistry eventListenerRegistry =
serviceRegistry.getService(EventListenerRegistry.class);


TranslationUpdateListener updateListener =
(TranslationUpdateListener) Component
.getInstance(TranslationUpdateListener.class);
log.info("register event listener: {}", updateListener);
eventListenerRegistry.appendListeners(EventType.POST_UPDATE,
updateListener);
eventListenerRegistry.appendListeners(EventType.POST_INSERT,
updateListener);
}

@Override
public void integrate(MetadataImplementor metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
}

@Override
public void disintegrate(SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
}
}
@@ -0,0 +1,206 @@
package org.zanata.webtrans.server;

import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpSession;

import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.contexts.SessionContext;
import org.jboss.seam.util.Work;
import org.jboss.seam.web.ServletContexts;
import org.jboss.seam.web.Session;
import org.zanata.common.ContentState;
import org.zanata.common.LocaleId;
import org.zanata.common.ProjectType;
import org.zanata.events.TextFlowTargetUpdateContextEvent;
import org.zanata.model.HDocument;
import org.zanata.model.HProjectIteration;
import org.zanata.model.HTextFlow;
import org.zanata.model.HTextFlowTarget;
import org.zanata.webtrans.server.rpc.TransUnitTransformer;
import org.zanata.webtrans.shared.auth.EditorClientId;
import org.zanata.webtrans.shared.model.DocumentId;
import org.zanata.webtrans.shared.model.ProjectIterationId;
import org.zanata.webtrans.shared.model.TransUnit;
import org.zanata.webtrans.shared.model.TransUnitId;
import org.zanata.webtrans.shared.model.TransUnitUpdateInfo;
import org.zanata.webtrans.shared.model.WorkspaceId;
import org.zanata.webtrans.shared.rpc.TransUnitUpdated;
import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
* @author Patrick Huang <a
* href="mailto:pahuang@redhat.com">pahuang@redhat.com</a>
*/
@Name("translationUpdateListener")
@Scope(ScopeType.APPLICATION)
@AutoCreate
@Slf4j
public class TranslationUpdateListener implements PostUpdateEventListener,
PostInsertEventListener {

private static final long serialVersionUID = 1L;
private static final Cache<CacheKey, CacheValue> updateContext =
CacheBuilder.newBuilder().softValues()
.expireAfterAccess(1, TimeUnit.SECONDS).build();

@In(create = true)
private TranslationWorkspaceManager translationWorkspaceManager;

@In
private TransUnitTransformer transUnitTransformer;

@Observer(TextFlowTargetUpdateContextEvent.EVENT_NAME)
public static void updateContext(TextFlowTargetUpdateContextEvent event) {
updateContext
.put(new CacheKey(event.getTransUnitId(), event.getLocaleId()),
new CacheValue(event.getEditorClientId(), event
.getUpdateType()));
}

@Override
public void onPostUpdate(final PostUpdateEvent event) {
Object entity = event.getEntity();
if (!(entity instanceof HTextFlowTarget)) {
return;
}

try {
new Work<Void>() {
@Override
protected Void work() throws Exception {
ContentState oldContentState =
(ContentState) Iterables.find(
Lists.newArrayList(event.getOldState()),
Predicates.instanceOf(ContentState.class));

HTextFlowTarget target =
HTextFlowTarget.class.cast(event.getEntity());
publishTransUnitUpdatedEvent(target.getVersionNum() - 1,
oldContentState, target);
return null;
}
}.workInTransaction();
} catch (Exception e) {
log.error("fail to publish TransUnitUpdate event", e);
}

}

private void publishTransUnitUpdatedEvent(int previousVersionNum,
ContentState previousState, HTextFlowTarget target) {
LocaleId localeId = target.getLocaleId();
HTextFlow textFlow = target.getTextFlow();
HDocument document = textFlow.getDocument();
HProjectIteration projectIteration = document.getProjectIteration();
String iterationSlug = projectIteration.getSlug();
String projectSlug = projectIteration.getProject().getSlug();
ProjectType projectType = projectIteration.getProjectType();

WorkspaceId workspaceId =
new WorkspaceId(new ProjectIterationId(projectSlug,
iterationSlug, projectType), localeId);
Optional<TranslationWorkspace> workspaceOptional =
translationWorkspaceManager.tryGetWorkspace(workspaceId);
if (!workspaceOptional.isPresent()) {
return;
}

TransUnit transUnit =
transUnitTransformer.transform(textFlow, target,
target.getLocale());

DocumentId documentId =
new DocumentId(document.getId(), document.getDocId());
int wordCount = textFlow.getWordCount().intValue();

TransUnitUpdateInfo updateInfo =
createTransUnitUpdateInfo(transUnit, documentId, wordCount,
previousVersionNum, previousState);

CacheValue context =
updateContext.getIfPresent(new CacheKey(transUnit.getId(),
transUnit.getLocaleId()));
TransUnitUpdated updated;
if (context != null) {
EditorClientId editorClientId = context.editorClientId;
TransUnitUpdated.UpdateType updateType = context.updateType;
updated =
new TransUnitUpdated(updateInfo, editorClientId, updateType);
log.debug("about to publish trans unit updated event {}", updated);
} else if (ServletContexts.instance().getRequest() != null) {

String sessionId = ServletContexts.instance().getRequest().getSession()
.getId();
EditorClientId editorClientId = new EditorClientId(sessionId, -1);
updated = new TransUnitUpdated(updateInfo, editorClientId,
TransUnitUpdated.UpdateType.NonEditorSave);
} else {
updated = new TransUnitUpdated(updateInfo, new EditorClientId("unknown", -1),
TransUnitUpdated.UpdateType.NonEditorSave);
}
workspaceOptional.get().publish(updated);
}

private static TransUnitUpdateInfo createTransUnitUpdateInfo(
TransUnit transUnit, DocumentId documentId, int wordCount,
int previousVersionNum, ContentState previousState) {
return new TransUnitUpdateInfo(true, true, documentId, transUnit,
wordCount, previousVersionNum, previousState, null);
}

@Override
public void onPostInsert(final PostInsertEvent event) {
Object entity = event.getEntity();
if (!(entity instanceof HTextFlowTarget)) {
return;
}
try {
new Work<Void>() {

@Override
protected Void work() throws Exception {
HTextFlowTarget target =
HTextFlowTarget.class.cast(event.getEntity());
publishTransUnitUpdatedEvent(0, ContentState.New, target);
return null;
}
}.workInTransaction();
} catch (Exception e) {
log.error("fail to publish TransUnitUpdate event", e);
}

}

@RequiredArgsConstructor
@EqualsAndHashCode
private static class CacheKey {
private final TransUnitId transUnitId;
private final LocaleId localeId;
}

@RequiredArgsConstructor
private static class CacheValue {
private final EditorClientId editorClientId;
private final TransUnitUpdated.UpdateType updateType;
}
}
Expand Up @@ -23,6 +23,7 @@

import org.zanata.webtrans.shared.NoSuchWorkspaceException;
import org.zanata.webtrans.shared.model.WorkspaceId;
import com.google.common.base.Optional;

/**
* @author Sean Flanigan <a
Expand All @@ -31,7 +32,8 @@
*/
public interface TranslationWorkspaceManager {

public TranslationWorkspace getOrRegisterWorkspace(WorkspaceId workspaceId)
TranslationWorkspace getOrRegisterWorkspace(WorkspaceId workspaceId)
throws NoSuchWorkspaceException;

Optional<TranslationWorkspace> tryGetWorkspace(WorkspaceId workspaceId);
}
Expand Up @@ -46,6 +46,7 @@
import org.zanata.webtrans.shared.rpc.ExitWorkspace;
import org.zanata.webtrans.shared.rpc.WorkspaceContextUpdate;

import com.google.common.base.Optional;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
Expand Down Expand Up @@ -257,6 +258,11 @@ public TranslationWorkspace getOrRegisterWorkspace(WorkspaceId workspaceId)
return workspace;
}

@Override
public Optional<TranslationWorkspace> tryGetWorkspace(WorkspaceId workspaceId) {
return Optional.fromNullable(workspaceMap.get(workspaceId));
}

private WorkspaceContext validateAndGetWorkspaceContext(
WorkspaceId workspaceId) throws NoSuchWorkspaceException {
String projectSlug =
Expand Down
Expand Up @@ -24,10 +24,13 @@

import org.jboss.seam.*;
import org.jboss.seam.annotations.*;
import org.jboss.seam.core.Events;
import org.zanata.events.TextFlowTargetUpdateContextEvent;
import org.zanata.model.*;
import org.zanata.service.*;
import org.zanata.service.TranslationService.*;
import org.zanata.webtrans.server.*;
import org.zanata.webtrans.shared.model.TransUnitUpdateInfo;
import org.zanata.webtrans.shared.rpc.*;
import org.zanata.webtrans.shared.rpc.TransUnitUpdated.*;

Expand Down Expand Up @@ -62,13 +65,25 @@ public UpdateTransUnitResult execute(RevertTransUnitUpdates action,
HLocale hLocale = securityCheckResult.getLocale();
TranslationWorkspace workspace = securityCheckResult.getWorkspace();

if (Events.exists()) {
for (TransUnitUpdateInfo updateInfo : action.getUpdatesToRevert()) {
Events.instance().raiseEvent(
TextFlowTargetUpdateContextEvent.EVENT_NAME,
new TextFlowTargetUpdateContextEvent(updateInfo
.getTransUnit().getId(), hLocale.getLocaleId(),
action.getEditorClientId(),
UpdateType.NonEditorSave));
}
}

List<TranslationResult> revertResults =
translationServiceImpl.revertTranslations(
hLocale.getLocaleId(), action.getUpdatesToRevert());


return transUnitUpdateHelper.generateUpdateTransUnitResult(
revertResults, action.getEditorClientId(), UpdateType.NonEditorSave,
workspace);
revertResults
);
}

@Override
Expand Down
Expand Up @@ -44,13 +44,11 @@ public class TransUnitUpdateHelper {
private TransUnitTransformer transUnitTransformer;

public UpdateTransUnitResult generateUpdateTransUnitResult(
List<TranslationService.TranslationResult> translationResults,
EditorClientId editorClientId,
TransUnitUpdated.UpdateType updateType,
TranslationWorkspace workspace) {
List<TranslationService.TranslationResult> translationResults) {
UpdateTransUnitResult result = new UpdateTransUnitResult();

for (TranslationService.TranslationResult translationResult : translationResults) {
// All these information is gathered in TranslationUpdateListener.
HTextFlowTarget newTarget =
translationResult.getTranslatedTextFlowTarget();
HTextFlow hTextFlow = newTarget.getTextFlow();
Expand All @@ -63,9 +61,6 @@ public UpdateTransUnitResult generateUpdateTransUnitResult(
.getDocument().getId(), hTextFlow.getDocument()
.getDocId()), tu, wordCount);

workspace.publish(new TransUnitUpdated(updateInfo, editorClientId,
updateType));

result.addUpdateResult(updateInfo);
}
return result;
Expand Down

0 comments on commit 8582b85

Please sign in to comment.