Package org.zanata.service.impl

Source Code of org.zanata.service.impl.CopyTransServiceImpl

/*
* Copyright 2010, Red Hat, Inc. and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.zanata.service.impl;

import java.util.List;
import java.util.concurrent.Future;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.zanata.async.Async;
import org.zanata.async.AsyncTaskResult;
import org.zanata.async.ContainsAsyncMethods;
import org.zanata.async.handle.CopyTransTaskHandle;
import org.zanata.dao.DocumentDAO;
import org.zanata.dao.ProjectDAO;
import org.zanata.dao.TextFlowDAO;
import org.zanata.dao.TextFlowTargetDAO;
import org.zanata.model.HCopyTransOptions;
import org.zanata.model.HDocument;
import org.zanata.model.HLocale;
import org.zanata.model.HProjectIteration;
import org.zanata.model.HTextFlow;
import org.zanata.service.CopyTransService;
import org.zanata.service.LocaleService;
import org.zanata.service.TranslationStateCache;
import org.zanata.util.ServiceLocator;
import com.google.common.base.Optional;
import com.google.common.base.Stopwatch;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.validation.constraints.NotNull;

@Name("copyTransServiceImpl")
@Scope(ScopeType.STATELESS)
@Slf4j
@ContainsAsyncMethods
@AllArgsConstructor
@NoArgsConstructor
public class CopyTransServiceImpl implements CopyTransService {

    private static final int COPY_TRANS_BATCH_SIZE = 20;

    @In
    private LocaleService localeServiceImpl;
    @In
    private ProjectDAO projectDAO;
    @In
    private DocumentDAO documentDAO;
    @In
    private CopyTransWorkFactory copyTransWorkFactory;
    @In
    private TextFlowTargetDAO textFlowTargetDAO;
    @In
    private TranslationStateCache translationStateCacheImpl;
    @In
    private TextFlowDAO textFlowDAO;

    /**
     * Copies previous matching translations for the given locale into a
     * document. Translations are matching if their document id, textflow id and
     * source content are identical, and their state is approved.
     *
     * The text flow revision for copied targets is set to the current text flow
     * revision.
     *
     * @param document
     *            the document to copy translations into
     * @param targetLocale
     *            the locale of translations to copy
     */
    private void copyTransForDocumentLocale(HDocument document,
            final HLocale targetLocale, final HCopyTransOptions options,
            Optional<CopyTransTaskHandle> taskHandleOpt) {

        int numCopied = 0;
        int start = 0;

        // need to reload HDocument because of different hibernate session
        document = documentDAO.findById(document.getId());

        // heuristic optimization
        Stopwatch stopwatch = new Stopwatch().start();
        boolean hasTranslationToCopy = true;
        if (options.getDocIdMismatchAction() ==
                HCopyTransOptions.ConditionRuleAction.REJECT) {
            long translationCandidate =
                    textFlowTargetDAO
                            .getTranslationCandidateCountWithDocIdAndLocale(
                                    document, targetLocale);
            hasTranslationToCopy = (translationCandidate != 0);
        }
        if (hasTranslationToCopy && options.getProjectMismatchAction() ==
                HCopyTransOptions.ConditionRuleAction.REJECT) {
            long translationCandidate =
                    textFlowTargetDAO
                            .getTranslationCandidateCountWithProjectAndLocale(
                                    document,
                                    targetLocale);
            hasTranslationToCopy = (translationCandidate != 0);
        }
        // TODO if the translation candidate number is small (compare to large
        // number of copy targets), it's better to inverse the process, i.e.
        // iterate through candidates and inject matches

        if (hasTranslationToCopy) {
            boolean requireTranslationReview =
                    document.getProjectIteration().getRequireTranslationReview();

            while (start < document.getTextFlows().size()) {
                numCopied +=
                        copyTransForBatch(document, start, COPY_TRANS_BATCH_SIZE,
                                targetLocale, options, taskHandleOpt,
                                requireTranslationReview);
                start += COPY_TRANS_BATCH_SIZE;
                documentDAO.clear();
            }
        } else if (taskHandleOpt.isPresent()) {
            int totalActiveTextFlows =
                    ServiceLocator.instance().getInstance(TextFlowDAO.class)
                            .countActiveTextFlowsInDocument(
                                    document.getId());

            taskHandleOpt.get().increaseProgress(totalActiveTextFlows);
        }

        // If there have been any changes to the document stats, reset them
        if( numCopied > 0 ) {
            translationStateCacheImpl.clearDocumentStatistics(document.getId(),
                    targetLocale.getLocaleId());
        }

        stopwatch.stop();
        log.info(
                "copyTrans: {} {} translations for document \"{}{}\" - duration: {}",
                numCopied, targetLocale.getLocaleId(), document.getPath(),
                document.getName(), stopwatch);
    }

    /**
     * Perform copy trans on a batch of text flows for a document.
     *
     * @param requireTranslationReview
     *            whether the project iteration requires translation review
     * @param batchStart
     *            USE_HIBERNATE_SEARCH The text flow position to start copying.
     * @param batchLength
     *            The number of text flows on which to perform copy trans,
     *            starting from batchStart.
     * @return The number of actual copied translations for the segment.
     */
    private int copyTransForBatch(HDocument document, final int batchStart,
            final int batchLength, final HLocale targetLocale,
            final HCopyTransOptions options,
            Optional<CopyTransTaskHandle> taskHandleOpt,
            boolean requireTranslationReview) {

        try {
            HDocument hDocument = documentDAO.findById(document.getId());
            List<HTextFlow> docTextFlows = hDocument.getTextFlows();
            int batchEnd =
                    Math.min(batchStart + batchLength, docTextFlows.size());
            int batchSize = batchEnd - batchStart;
            List<HTextFlow> copyTargets =
                    docTextFlows.subList(batchStart, batchEnd);
            Integer numCopied =
                    copyTransWorkFactory.createCopyTransWork(targetLocale,
                            options, document, requireTranslationReview,
                            copyTargets)
                            .workInTransaction();
            if (taskHandleOpt.isPresent()) {
                taskHandleOpt.get().increaseProgress(batchSize);
            }
            return numCopied;
        } catch (Exception e) {
            log.warn("exception during copy trans", e);
            return 0;
        }
    }

    @Override
    public void copyTransForDocument(HDocument document, CopyTransTaskHandle handle) {
        copyTransForDocument(document, null, handle);
    }

    @Override
    public void copyTransForDocument(HDocument document,
            HCopyTransOptions copyTransOpts, CopyTransTaskHandle handle) {

        Optional<CopyTransTaskHandle> taskHandleOpt =
                Optional.fromNullable(handle);
        if( taskHandleOpt.isPresent() ) {
            prepareCopyTransHandle(document, taskHandleOpt.get());
        }

        // use project level options
        if (copyTransOpts == null) {
            // NB: Need to reload the options from the db
            copyTransOpts =
                    projectDAO
                            .findById(
                                    document.getProjectIteration().getProject()
                                            .getId(), false)
                            .getDefaultCopyTransOpts();
        }
        // use the global default options
        if (copyTransOpts == null) {
            copyTransOpts = new HCopyTransOptions();
        }

        log.info("copyTrans start: document \"{}\"", document.getDocId());
        List<HLocale> localeList =
                localeServiceImpl.getSupportedLanguageByProjectIteration(
                        document.getProjectIteration().getProject().getSlug(),
                        document.getProjectIteration().getSlug());

        for (HLocale targetLocale : localeList) {
            if (taskHandleOpt.isPresent() && taskHandleOpt.get().isCancelled()) {
                return;
            }
            copyTransForDocumentLocale(document, targetLocale, copyTransOpts,
                    taskHandleOpt);
        }
        log.info("copyTrans finished: document \"{}\"", document.getDocId());
    }

    @Override
    @Async
    public Future<Void> startCopyTransForDocument(HDocument document,
            HCopyTransOptions copyTransOptions, CopyTransTaskHandle handle) {
        copyTransForDocument(document, copyTransOptions, handle);
        return AsyncTaskResult.taskResult();
    }

    @Override
    @Async
    public Future<Void> startCopyTransForIteration(HProjectIteration iteration,
            HCopyTransOptions copyTransOptions, CopyTransTaskHandle handle) {
        copyTransForIteration(iteration, copyTransOptions, handle);
        return AsyncTaskResult.taskResult();
    }

    @Override
    public void copyTransForIteration(HProjectIteration iteration,
            HCopyTransOptions copyTransOptions,
            @NotNull CopyTransTaskHandle handle) {
        Optional<CopyTransTaskHandle> taskHandleOpt =
                Optional.fromNullable(handle);

        if( taskHandleOpt.isPresent() ) {
            prepareCopyTransHandle(iteration, taskHandleOpt.get());
        }

        for (HDocument doc : iteration.getDocuments().values()) {
            if (taskHandleOpt.isPresent() && taskHandleOpt.get().isCancelled()) {
                return;
            }
            // if options are to reject translation from other projects and there is
            // only one version in current project, don't even bother running
            // copyTrans
            if (copyTransOptions.getProjectMismatchAction() == HCopyTransOptions.ConditionRuleAction.REJECT) {
                int copyCandidates = projectDAO.getTranslationCandidateCount(
                        iteration.getProject().getId());
                if (copyCandidates < 2) {
                    if (taskHandleOpt.isPresent()) {
                        taskHandleOpt.get().increaseProgress(
                                taskHandleOpt.get().getMaxProgress());
                    }
                    return;
                }
            }
            this.copyTransForDocument(doc, copyTransOptions, handle);
        }
    }

    private void prepareCopyTransHandle( HProjectIteration iteration, CopyTransTaskHandle handle ) {
        if( !handle.isPrepared() ) {
            // TODO Progress should be handle as long
            handle.setMaxProgress( (int)getMaxProgress(iteration) );
            handle.setPrepared();
        }
    }

    private void prepareCopyTransHandle( HDocument document, CopyTransTaskHandle handle ) {
        if( !handle.isPrepared() ) {
            // TODO Progress should be handle as long
            handle.setMaxProgress( (int)getMaxProgress(document) );
            handle.setPrepared();
        }
    }

    private long getMaxProgress(HProjectIteration iteration) {
        log.debug("counting locales");
        List<HLocale> localeList =
                localeServiceImpl.getSupportedLanguageByProjectIteration(
                        iteration.getProject().getSlug(),
                        iteration.getSlug());
        int localeCount = localeList.size();
        log.debug("counting locales finished");
        log.debug("counting textflows");
        long textFlowCount = textFlowDAO.countActiveTextFlowsInProjectIteration(
                iteration.getId());
        log.debug("counting textflows finished");
        return localeCount * textFlowCount;
    }

    private long getMaxProgress(HDocument document) {
        List<HLocale> localeList =
                localeServiceImpl.getSupportedLanguageByProjectIteration(document
                        .getProjectIteration().getProject().getSlug(), document
                        .getProjectIteration().getSlug());
        int localeCount = localeList.size();

        int textFlowCount =
                textFlowDAO.countActiveTextFlowsInDocument(document.getId());
        return localeCount * textFlowCount;
    }

}
TOP

Related Classes of org.zanata.service.impl.CopyTransServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.