From b8745c8071bdc7ed5a3692f4022a65306f5681a3 Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Wed, 2 May 2012 13:06:19 +1000 Subject: [PATCH 1/5] Implement document uploading through the GUI. Initially only supports PO files. Other formats should come later. Minor style changes when uploading files. --- .../action/ProjectIterationFilesAction.java | 158 ++++++++++++++++-- .../action/TranslationFileUploadHelper.java | 78 --------- .../service/TranslationFileService.java | 3 + .../zanata/service/TranslationService.java | 17 ++ .../impl/TranslationFileServiceImpl.java | 53 +++++- .../service/impl/TranslationServiceImpl.java | 96 +++++++++-- .../src/main/resources/messages.properties | 2 + .../src/main/webapp/iteration/files.xhtml | 54 +++++- 8 files changed, 353 insertions(+), 108 deletions(-) delete mode 100644 server/zanata-war/src/main/java/org/zanata/action/TranslationFileUploadHelper.java diff --git a/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java b/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java index e877e99ccb..aaa666a012 100644 --- a/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java +++ b/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java @@ -40,12 +40,14 @@ import org.zanata.model.HProjectIteration; import org.zanata.rest.StringSet; import org.zanata.rest.dto.extensions.ExtensionType; +import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TextFlowTarget; import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.security.ZanataIdentity; import org.zanata.service.TranslationFileService; import org.zanata.service.TranslationService; +import java.io.InputStream; import java.util.Collection; import java.util.List; @@ -84,13 +86,16 @@ public class ProjectIterationFilesAction private String documentNameFilter; - private TranslationFileUploadHelper fileUploadHelper; + private TranslationFileUploadHelper translationFileUpload; + + private DocumentFileUploadHelper documentFileUpload; public void initialize() { this.iterationDocuments = this.documentDAO.getAllByProjectIteration(this.projectSlug, this.iterationSlug); - this.fileUploadHelper = new TranslationFileUploadHelper(); + this.translationFileUpload = new TranslationFileUploadHelper(); + this.documentFileUpload = new DocumentFileUploadHelper(); } public HLocale getLocale() @@ -119,20 +124,20 @@ public TransUnitWords getTransUnitWordsForDocument(HDocument doc) } @Restrict("#{projectIterationFilesAction.fileUploadAllowed}") - public void uploadFile() + public void uploadTranslationFile() { TranslationsResource transRes = null; try { // process the file - transRes = this.translationFileServiceImpl.parseTranslationFile(this.fileUploadHelper.getFileContents(), - this.fileUploadHelper.getFileName()); + transRes = this.translationFileServiceImpl.parseTranslationFile(this.translationFileUpload.getFileContents(), + this.translationFileUpload.getFileName()); // translate it Collection resourcesNotFound = - this.translationServiceImpl.translateAll(this.projectSlug, this.iterationSlug, this.fileUploadHelper.getDocId(), + this.translationServiceImpl.translateAll(this.projectSlug, this.iterationSlug, this.translationFileUpload.getDocId(), new LocaleId(this.localeId), transRes, new StringSet(ExtensionType.GetText.toString()), - this.fileUploadHelper.getMergeTranslations() ? MergeType.AUTO : MergeType.IMPORT); + this.translationFileUpload.getMergeTranslations() ? MergeType.AUTO : MergeType.IMPORT); StringBuilder facesInfoMssg = new StringBuilder("File {0} uploaded."); if( resourcesNotFound.size() > 0 ) @@ -140,7 +145,7 @@ public void uploadFile() facesInfoMssg.append(" There were some warnings, see below."); } - FacesMessages.instance().add(Severity.INFO, facesInfoMssg.toString(), this.fileUploadHelper.getFileName()); + FacesMessages.instance().add(Severity.INFO, facesInfoMssg.toString(), this.translationFileUpload.getFileName()); for( TextFlowTarget nf : resourcesNotFound ) { FacesMessages.instance().add(Severity.WARN, "Could not find text flow for message: {0}", nf.getContents()); @@ -148,7 +153,29 @@ public void uploadFile() } catch (ZanataServiceException zex) { - FacesMessages.instance().add(Severity.ERROR, "Invalid file type: {0}", this.fileUploadHelper.getFileName()); + FacesMessages.instance().add(Severity.ERROR, zex.getMessage(), this.translationFileUpload.getFileName()); + } + } + + @Restrict("#{projectIterationFilesAction.documentUploadAllowed}") + public void uploadDocumentFile() + { + try + { + Resource doc = this.translationFileServiceImpl.parseDocumentFile(this.documentFileUpload.getFileContents(), + this.documentFileUpload.getDocumentPath(), this.documentFileUpload.getFileName()); + + // TODO Copy Trans values + // Extensions are hard-coded to GetText, since it is the only supported format at the time + this.translationServiceImpl.saveDocument(this.projectSlug, this.iterationSlug, + this.documentFileUpload.getDocumentPath() + doc.getName(), doc, new StringSet(ExtensionType.GetText.toString()), + false); + + FacesMessages.instance().add(Severity.INFO, "Document file {0} uploaded.", this.documentFileUpload.getFileName()); + } + catch (ZanataServiceException zex) + { + FacesMessages.instance().add(Severity.ERROR, zex.getMessage(), this.documentFileUpload.getFileName()); } } @@ -161,6 +188,13 @@ public boolean isFileUploadAllowed() && identity != null && identity.hasPermission("modify-translation", projectIteration, hLocale); } + public boolean isDocumentUploadAllowed() + { + HProjectIteration projectIteration = this.projectIterationDAO.getBySlug(projectSlug, iterationSlug); + return projectIteration.getStatus() == EntityStatus.ACTIVE + && identity != null && identity.hasPermission("import-template", projectIteration); + } + public List getIterationDocuments() { return iterationDocuments; @@ -211,8 +245,110 @@ public void setDocumentNameFilter(String documentNameFilter) this.documentNameFilter = documentNameFilter; } - public TranslationFileUploadHelper getFileUploadHelper() + public TranslationFileUploadHelper getTranslationFileUpload() + { + return translationFileUpload; + } + + public DocumentFileUploadHelper getDocumentFileUpload() + { + return documentFileUpload; + } + + /** + * Helper class to upload translation files. + */ + public static class TranslationFileUploadHelper + { + private String docId; + + private InputStream fileContents; + + private String fileName; + + private boolean mergeTranslations = true; // Merge by default + + + public String getDocId() + { + return docId; + } + + public void setDocId(String docId) + { + this.docId = docId; + } + + public InputStream getFileContents() + { + return fileContents; + } + + public void setFileContents(InputStream fileContents) + { + this.fileContents = fileContents; + } + + public String getFileName() + { + return fileName; + } + + public void setFileName(String fileName) + { + this.fileName = fileName; + } + + public boolean getMergeTranslations() + { + return mergeTranslations; + } + + public void setMergeTranslations(boolean mergeTranslations) + { + this.mergeTranslations = mergeTranslations; + } + } + + /** + * Helper class to upload documents. + */ + public static class DocumentFileUploadHelper { - return fileUploadHelper; + private InputStream fileContents; + + private String fileName; + + private String documentPath; + + public InputStream getFileContents() + { + return fileContents; + } + + public void setFileContents(InputStream fileContents) + { + this.fileContents = fileContents; + } + + public String getFileName() + { + return fileName; + } + + public void setFileName(String fileName) + { + this.fileName = fileName; + } + + public String getDocumentPath() + { + return documentPath; + } + + public void setDocumentPath(String documentPath) + { + this.documentPath = documentPath; + } } } diff --git a/server/zanata-war/src/main/java/org/zanata/action/TranslationFileUploadHelper.java b/server/zanata-war/src/main/java/org/zanata/action/TranslationFileUploadHelper.java deleted file mode 100644 index 50f9aec6e9..0000000000 --- a/server/zanata-war/src/main/java/org/zanata/action/TranslationFileUploadHelper.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.action; - -import java.io.InputStream; - -/** - * @author Carlos Munoz camunoz@redhat.com - */ -public class TranslationFileUploadHelper -{ - private String docId; - - private InputStream fileContents; - - private String fileName; - - private boolean mergeTranslations = true; // Merge by default - - - public String getDocId() - { - return docId; - } - - public void setDocId(String docId) - { - this.docId = docId; - } - - public InputStream getFileContents() - { - return fileContents; - } - - public void setFileContents(InputStream fileContents) - { - this.fileContents = fileContents; - } - - public String getFileName() - { - return fileName; - } - - public void setFileName(String fileName) - { - this.fileName = fileName; - } - - public boolean getMergeTranslations() - { - return mergeTranslations; - } - - public void setMergeTranslations(boolean mergeTranslations) - { - this.mergeTranslations = mergeTranslations; - } -} diff --git a/server/zanata-war/src/main/java/org/zanata/service/TranslationFileService.java b/server/zanata-war/src/main/java/org/zanata/service/TranslationFileService.java index b930f17a6c..5982c8ee26 100644 --- a/server/zanata-war/src/main/java/org/zanata/service/TranslationFileService.java +++ b/server/zanata-war/src/main/java/org/zanata/service/TranslationFileService.java @@ -20,6 +20,7 @@ */ package org.zanata.service; +import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TranslationsResource; import java.io.InputStream; @@ -32,4 +33,6 @@ public interface TranslationFileService { TranslationsResource parseTranslationFile(InputStream fileContents, String fileName); + + Resource parseDocumentFile(InputStream fileContents, String path, String fileName); } diff --git a/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java b/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java index 3d9da74736..11e8fe321b 100644 --- a/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java +++ b/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java @@ -22,8 +22,10 @@ import org.zanata.common.ContentState; import org.zanata.common.LocaleId; import org.zanata.common.MergeType; +import org.zanata.model.HDocument; import org.zanata.model.HTextFlow; import org.zanata.model.HTextFlowTarget; +import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TextFlowTarget; import org.zanata.rest.dto.resource.TranslationsResource; @@ -47,6 +49,21 @@ public interface TranslationService Collection translateAll(String projectSlug, String iterationSlug, String docId, LocaleId locale, TranslationsResource translations, Set extensions, MergeType mergeType); + /** + * Creates or Updates a document. + * + * @param projectSlug The document's project id. + * @param iterationSlug The document's project iteration id. + * @param docId The document id. + * @param sourceDoc The document contents. + * @param extensions Document extensions to save. + * @param copyTrans Whether to copy translations from other projects or not. A true value does not guarantee that + * this will happen, it is only a suggestion. + * @return The created / updated document + */ + public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, + Set extensions, boolean copyTrans ); + public interface TranslationResult { HTextFlow getTextFlow(); diff --git a/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java b/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java index 4ecdb24c61..969dc00600 100644 --- a/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java +++ b/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java @@ -26,8 +26,10 @@ import org.jboss.seam.annotations.Scope; import org.xml.sax.InputSource; import org.zanata.adapter.po.PoReader2; +import org.zanata.common.LocaleId; import org.zanata.dao.DocumentDAO; import org.zanata.exception.ZanataServiceException; +import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.service.TranslationFileService; @@ -50,7 +52,14 @@ public TranslationsResource parseTranslationFile(InputStream fileContents, Strin { if( fileName.endsWith(".po") ) { - return this.parsePoFile(fileContents); + try + { + return this.parsePoFile(fileContents); + } + catch (Exception e) + { + throw new ZanataServiceException("Invalid PO file contents on file: " + fileName); + } } else { @@ -58,9 +67,51 @@ public TranslationsResource parseTranslationFile(InputStream fileContents, Strin } } + public Resource parseDocumentFile(InputStream fileContents, String path, String fileName) + { + if( fileName.endsWith(".pot") ) + { + // remove the .pot extension + fileName = fileName.substring(0, fileName.lastIndexOf('.')); + + try + { + return this.parsePotFile(fileContents, path, fileName); + } + catch (Exception e) + { + throw new ZanataServiceException("Invalid POT file contents on file: " + fileName); + } + } + else + { + throw new ZanataServiceException("Unsupported Document file: " + fileName); + } + } + private TranslationsResource parsePoFile( InputStream fileContents ) { PoReader2 poReader = new PoReader2(); return poReader.extractTarget(new InputSource(fileContents) ); } + + private Resource parsePotFile( InputStream fileContents, String docPath, String fileName ) + { + PoReader2 poReader = new PoReader2(); + // assume english as source locale + Resource res = poReader.extractTemplate(new InputSource(fileContents), new LocaleId("en"), fileName); + // get rid of leading slashes ("/") + if( docPath.startsWith("/") ) + { + docPath = docPath.substring(1); + } + // Add a trailing slash ("/") if there isn't one + if( !docPath.endsWith("/") ) + { + docPath = docPath.concat("/"); + } + + res.setName( docPath + fileName ); + return res; + } } diff --git a/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java b/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java index 8105b0833f..63ff0ecc4b 100644 --- a/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java +++ b/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java @@ -15,14 +15,9 @@ */ package org.zanata.service.impl; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import javax.annotation.Nullable; - +import com.google.common.base.Predicate; +import com.google.common.base.Strings; +import com.google.common.collect.Collections2; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.hibernate.Session; @@ -35,9 +30,11 @@ import org.jboss.seam.log.Log; import org.jboss.seam.log.Logging; import org.jboss.seam.security.management.JpaIdentityStore; +import org.zanata.ApplicationConfiguration; import org.zanata.common.ContentState; import org.zanata.common.EntityStatus; import org.zanata.common.LocaleId; +import org.zanata.common.MergeType; import org.zanata.dao.DocumentDAO; import org.zanata.dao.PersonDAO; import org.zanata.dao.ProjectDAO; @@ -56,16 +53,22 @@ import org.zanata.model.HTextFlow; import org.zanata.model.HTextFlowTarget; import org.zanata.rest.dto.extensions.ExtensionType; +import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TextFlowTarget; import org.zanata.rest.dto.resource.TranslationsResource; -import org.zanata.common.MergeType; import org.zanata.rest.service.ResourceUtils; +import org.zanata.service.CopyTransService; import org.zanata.service.LocaleService; import org.zanata.service.TranslationService; import org.zanata.webtrans.server.TranslationWorkspaceManager; -import com.google.common.base.Predicate; -import com.google.common.base.Strings; -import com.google.common.collect.Collections2; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import static org.zanata.util.StringUtil.allEmpty; import static org.zanata.util.StringUtil.allNonEmpty; @@ -112,6 +115,12 @@ public class TranslationServiceImpl implements TranslationService @In private LocaleService localeServiceImpl; + @In + private CopyTransService copyTransServiceImpl; + + @In + private ApplicationConfiguration applicationConfiguration; + @In(value = JpaIdentityStore.AUTHENTICATED_USER, scope = ScopeType.SESSION) private HAccount authenticatedAccount; @@ -359,6 +368,56 @@ else if (incomingTarget.getState() == ContentState.Approved) return unknownResIds; } + public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, + Set extensions, boolean copyTrans ) + { + HProjectIteration hProjectIteration = retrieveAndCheckIteration(projectSlug, iterationSlug, true); + + validateExtensions(extensions); + + HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, docId); + HLocale hLocale = this.localeServiceImpl.validateSourceLocale( sourceDoc.getLang() ); + + boolean changed = false; + int nextDocRev; + if (document == null) + { // must be a create operation + nextDocRev = 1; + changed = true; + // TODO check that entity name matches id parameter + document = new HDocument(sourceDoc.getName(), sourceDoc.getContentType(), hLocale); + document.setProjectIteration(hProjectIteration); + hProjectIteration.getDocuments().put(docId, document); + } + else if (document.isObsolete()) + { // must also be a create operation + nextDocRev = document.getRevision() + 1; + changed = true; + document.setObsolete(false); + // not sure if this is needed + hProjectIteration.getDocuments().put(docId, document); + } + else + { // must be an update operation + nextDocRev = document.getRevision() + 1; + } + + changed |= resourceUtils.transferFromResource(sourceDoc, document, extensions, hLocale, nextDocRev); + + if (changed) + { + document = documentDAO.makePersistent(document); + documentDAO.flush(); + } + + if (copyTrans && nextDocRev == 1) + { + copyClosestEquivalentTranslation(document); + } + + return document; + } + private void determineContentState(Long textFlowId, ContentState stateToSet, List contentToSave, HTextFlowTarget target) { Collection emptyContents = getEmptyContents(contentToSave); @@ -472,6 +531,19 @@ public static void validateExtensions(Set requestedExt) } } + /** + * Invoke the copy trans function for a document. + * + * @param document The document to copy translations into. + */ + private void copyClosestEquivalentTranslation(HDocument document) + { + if (applicationConfiguration.getEnableCopyTrans()) + { + copyTransServiceImpl.copyTransForDocument(document); + } + } + public static class TranslationResultImpl implements TranslationResult { private HTextFlow textFlow; diff --git a/server/zanata-war/src/main/resources/messages.properties b/server/zanata-war/src/main/resources/messages.properties index 812f3ee479..5c6e57c67c 100644 --- a/server/zanata-war/src/main/resources/messages.properties +++ b/server/zanata-war/src/main/resources/messages.properties @@ -239,6 +239,7 @@ jsf.iteration.ShowAllLocales=Show All Locales jsf.iteration.ShowAllLocales.title=Shows all available locales for this version (Teams for which you belong will be higlighted in yellow). jsf.iteration.files.ConfirmDownloadAllFiles=Your download will be prepared and may take a few minutes to complete. Is this ok? jsf.iteration.files.ContentType=Content Type +jsf.iteration.files.DocumentPath=Document Path jsf.iteration.files.dotpo=.po jsf.iteration.files.Download=Download jsf.iteration.files.DownloadAllFiles=Download All Files (zip) @@ -251,6 +252,7 @@ jsf.iteration.files.Path=Path jsf.iteration.files.ProcessDlgTitle=Processing project files... jsf.iteration.files.Statistics=Statistics jsf.iteration.files.Upload=Upload +jsf.iteration.files.UploadDocument=Upload Document jsf.iteration.files.UploadFile=Upload File jsf.iteration.stats.OpenInWebEditor=Open in Translation Editor diff --git a/server/zanata-war/src/main/webapp/iteration/files.xhtml b/server/zanata-war/src/main/webapp/iteration/files.xhtml index 08d46f4a02..1d8c0645c3 100644 --- a/server/zanata-war/src/main/webapp/iteration/files.xhtml +++ b/server/zanata-war/src/main/webapp/iteration/files.xhtml @@ -22,6 +22,7 @@ } function openUploadPanel(docId) { + #{rich:element('uploadPanelHeader')}.innerHTML = '#{messages['jsf.iteration.files.UploadFile']}: ' + docId; #{rich:element('uploadDocId')}.value = docId; #{rich:component('uploadPanel')}.show(); } @@ -30,6 +31,11 @@ #{rich:component('uploadPanel')}.hide(); return false; } + + function hideDocUploadPanel() { + #{rich:component('uploadDocPanel')}.hide(); + return false; + } @@ -179,19 +185,19 @@ resizeable="#{false}" autosized="#{true}"> - + + data="#{projectIterationFilesAction.translationFileUpload.fileContents}" + fileName="#{projectIterationFilesAction.translationFileUpload.fileName}"/> - - +
+ action="#{projectIterationFilesAction.uploadTranslationFile}"/>
@@ -210,9 +216,45 @@ action="#{projectIterationZipFileAction.prepareIterationZipFile}" onclick="if(!downloadAllFilesClick()){ return false; }" reRender="downloadProgressBar"/> + + #{messages['jsf.iteration.files.Upload']} Document + + + + + + + + + + + +
+ + +
+
+
+ \ No newline at end of file From 85f1583ddad22aa7ba4cff4fe7dc09d75a3a3d28 Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Thu, 3 May 2012 09:59:04 +1000 Subject: [PATCH 2/5] REST service refactoring. Move document writing business logic to a service to be used by both GUI and REST services. Create Document and Slug services to allow for business logic reuse. --- .../java/org/zanata/action/ProjectHome.java | 15 +- .../action/ProjectIterationFilesAction.java | 6 +- .../zanata/action/ProjectIterationHome.java | 18 +-- .../org/zanata/dao/ProjectIterationDAO.java | 11 +- .../zanata/rest/service/ResourceUtils.java | 76 +++++---- .../service/SourceDocResourceService.java | 111 +++---------- .../service/TranslatedDocResourceService.java | 6 +- .../org/zanata/service/DocumentService.java | 47 ++++++ .../org/zanata/service/SlugEntityService.java | 41 +++++ .../zanata/service/TranslationService.java | 15 -- .../service/impl/DocumentServiceImpl.java | 151 ++++++++++++++++++ .../service/impl/SlugEntityServiceImpl.java | 51 ++++++ .../service/impl/TranslationServiceImpl.java | 133 +-------------- .../service/TranslationResourceRestTest.java | 14 +- 14 files changed, 404 insertions(+), 291 deletions(-) create mode 100644 server/zanata-war/src/main/java/org/zanata/service/DocumentService.java create mode 100644 server/zanata-war/src/main/java/org/zanata/service/SlugEntityService.java create mode 100644 server/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java create mode 100644 server/zanata-war/src/main/java/org/zanata/service/impl/SlugEntityServiceImpl.java diff --git a/server/zanata-war/src/main/java/org/zanata/action/ProjectHome.java b/server/zanata-war/src/main/java/org/zanata/action/ProjectHome.java index 92bd6ed5e3..36cc2a70c7 100644 --- a/server/zanata-war/src/main/java/org/zanata/action/ProjectHome.java +++ b/server/zanata-war/src/main/java/org/zanata/action/ProjectHome.java @@ -47,6 +47,7 @@ import org.zanata.model.HLocale; import org.zanata.model.HProjectIteration; import org.zanata.service.LocaleService; +import org.zanata.service.SlugEntityService; @Name("projectHome") public class ProjectHome extends SlugHome @@ -75,6 +76,9 @@ public class ProjectHome extends SlugHome @In LocaleService localeServiceImpl; + @In + SlugEntityService slugEntityServiceImpl; + @In(create = true) ProjectDAO projectDAO; @@ -116,16 +120,7 @@ public boolean validateSlug(String slug, String componentId) public boolean isSlugAvailable(String slug) { - try - { - getEntityManager().createQuery("from HProject p where p.slug = :slug").setParameter("slug", slug).getSingleResult(); - return false; - } - catch (NoResultException e) - { - // pass - } - return true; + return slugEntityServiceImpl.isSlugAvailable(slug, HIterationProject.class); } @Override diff --git a/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java b/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java index aaa666a012..7b2a2f3c4c 100644 --- a/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java +++ b/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java @@ -44,6 +44,7 @@ import org.zanata.rest.dto.resource.TextFlowTarget; import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.security.ZanataIdentity; +import org.zanata.service.DocumentService; import org.zanata.service.TranslationFileService; import org.zanata.service.TranslationService; @@ -82,6 +83,9 @@ public class ProjectIterationFilesAction @In private TranslationService translationServiceImpl; + @In + private DocumentService documentServiceImpl; + private List iterationDocuments; private String documentNameFilter; @@ -167,7 +171,7 @@ public void uploadDocumentFile() // TODO Copy Trans values // Extensions are hard-coded to GetText, since it is the only supported format at the time - this.translationServiceImpl.saveDocument(this.projectSlug, this.iterationSlug, + this.documentServiceImpl.saveDocument(this.projectSlug, this.iterationSlug, this.documentFileUpload.getDocumentPath() + doc.getName(), doc, new StringSet(ExtensionType.GetText.toString()), false); diff --git a/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationHome.java b/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationHome.java index c30c2711b3..e445264187 100644 --- a/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationHome.java +++ b/server/zanata-war/src/main/java/org/zanata/action/ProjectIterationHome.java @@ -40,6 +40,7 @@ import org.zanata.model.HLocale; import org.zanata.model.HProjectIteration; import org.zanata.service.LocaleService; +import org.zanata.service.SlugEntityService; @Name("projectIterationHome") public class ProjectIterationHome extends SlugHome @@ -51,13 +52,19 @@ public class ProjectIterationHome extends SlugHome private String slug; private String projectSlug; + @In(required = false) Map iterationCustomizedItems; + @In(required = false) private Boolean iterationOverrideLocales; + @In LocaleService localeServiceImpl; + @In + SlugEntityService slugEntityServiceImpl; + @Logger Log log; @@ -125,16 +132,7 @@ public boolean validateSlug(String slug, String componentId) public boolean isSlugAvailable(String slug) { - try - { - getEntityManager().createQuery("from HProjectIteration t where t.slug = :slug and t.project.slug = :projectSlug").setParameter("slug", slug).setParameter("projectSlug", projectSlug).getSingleResult(); - return false; - } - catch (NoResultException e) - { - // pass - } - return true; + return slugEntityServiceImpl.isSlugAvailable(slug, HProjectIteration.class); } @Override diff --git a/server/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java b/server/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java index 483dde20f4..3edf5f3b87 100644 --- a/server/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java +++ b/server/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java @@ -20,12 +20,6 @@ */ package org.zanata.dao; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.EntityTag; - import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.queryParser.ParseException; @@ -52,6 +46,11 @@ import org.zanata.model.StatusCount; import org.zanata.util.HashUtil; +import javax.ws.rs.core.EntityTag; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + @Name("projectIterationDAO") @AutoCreate @Scope(ScopeType.STATELESS) diff --git a/server/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java b/server/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java index 5fb1fec6f6..80ef1b8e9f 100644 --- a/server/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java +++ b/server/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java @@ -1,32 +1,6 @@ package org.zanata.rest.service; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.annotation.PostConstruct; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.fedorahosted.tennera.jgettext.HeaderFields; import org.jboss.seam.Component; @@ -53,6 +27,7 @@ import org.zanata.model.po.HPoTargetHeader; import org.zanata.model.po.HPotEntryData; import org.zanata.rest.dto.Person; +import org.zanata.rest.dto.extensions.ExtensionType; import org.zanata.rest.dto.extensions.comment.SimpleComment; import org.zanata.rest.dto.extensions.gettext.AbstractResourceMetaExtension; import org.zanata.rest.dto.extensions.gettext.HeaderEntry; @@ -70,6 +45,33 @@ import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.util.StringUtil; +import javax.annotation.PostConstruct; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + @Name("resourceUtils") @Scope(ScopeType.STATELESS) @AutoCreate @@ -989,8 +991,6 @@ private String getLanguageTeam(final HLocale hLocale) /** * Retrieves the language PO file header for a given locale. - * - * @param translations */ private String getLanguage(final HLocale locale) { @@ -1365,4 +1365,22 @@ public boolean transferToTranslationsResource(TranslationsResource transRes, HDo return found; } + /** + * Ensures that any extensions sent with the current query are valid for this + * context. + * + * @param requestedExt Extensions to be validated + */ + public static void validateExtensions(Set requestedExt) + { + Set validExtensions = ExtensionType.asStringSet(); + + if(!CollectionUtils.isSubCollection(requestedExt, validExtensions)) + { + @SuppressWarnings("unchecked") + Collection invalidExtensions = CollectionUtils.subtract(requestedExt, validExtensions); + throw new RuntimeException("Unsupported Extensions within this context: " + StringUtils.join(invalidExtensions, ",")); + } + } + } diff --git a/server/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java b/server/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java index 4d137770fc..20b5a04462 100644 --- a/server/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java +++ b/server/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java @@ -49,6 +49,7 @@ import org.zanata.rest.dto.resource.ResourceMeta; import org.zanata.rest.dto.resource.TextFlow; import org.zanata.service.CopyTransService; +import org.zanata.service.DocumentService; import org.zanata.service.LocaleService; import javax.ws.rs.Consumes; @@ -77,8 +78,6 @@ import java.util.List; import java.util.Set; -import static org.zanata.service.impl.TranslationServiceImpl.validateExtensions; - /** * @author Carlos Munoz camunoz@redhat.com */ @@ -108,9 +107,6 @@ public class SourceDocResourceService implements SourceDocResource @PathParam("iterationSlug") private String iterationSlug; - @In - private ProjectDAO projectDAO; - @In private ProjectIterationDAO projectIterationDAO; @@ -123,6 +119,9 @@ public class SourceDocResourceService implements SourceDocResource @In private CopyTransService copyTransServiceImpl; + @In + private DocumentService documentServiceImpl; + @In private ApplicationConfiguration applicationConfiguration; @@ -138,21 +137,21 @@ public SourceDocResourceService() } // @formatter:off - public SourceDocResourceService(ProjectDAO projectDAO, - ProjectIterationDAO projectIterationDAO, + public SourceDocResourceService(ProjectIterationDAO projectIterationDAO, DocumentDAO documentDAO, LocaleService localeService, CopyTransService copyTransService, + DocumentService documentService, ApplicationConfiguration applicationConfiguration, ResourceUtils resourceUtils, ETagUtils eTagUtils ) { - this.projectDAO = projectDAO; this.projectIterationDAO = projectIterationDAO; this.documentDAO = documentDAO; this.localeServiceImpl = localeService; this.copyTransServiceImpl = copyTransService; + this.documentServiceImpl = documentService; this.applicationConfiguration = applicationConfiguration; this.resourceUtils = resourceUtils; this.eTagUtils = eTagUtils; @@ -250,11 +249,11 @@ public Response post(Resource resource, @QueryParam("ext") Set extension { HProjectIteration hProjectIteration = retrieveAndCheckIteration(true); - validateExtensions(extensions); //gettext, comment + resourceUtils.validateExtensions(extensions); //gettext, comment HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, resource.getName()); - HLocale hLocale = validateSourceLocale(resource.getLang()); - int nextDocRev; + + // already existing non-obsolete document. if (document != null) { if (!document.isObsolete()) @@ -262,27 +261,12 @@ public Response post(Resource resource, @QueryParam("ext") Set extension // updates must happen through PUT on the actual resource return Response.status(Response.Status.CONFLICT).entity("A document with name " + resource.getName() + " already exists.").build(); } - // a deleted document is being created again - nextDocRev = document.getRevision() + 1; - document.setObsolete(false); } - else - { - nextDocRev = 1; - document = new HDocument(resource.getName(), resource.getContentType(), hLocale); - document.setProjectIteration(hProjectIteration); - } - hProjectIteration.getDocuments().put(resource.getName(), document); - resourceUtils.transferFromResource(resource, document, extensions, hLocale, nextDocRev); - - document = documentDAO.makePersistent(document); - documentDAO.flush(); - - if (copytrans && nextDocRev == 1) - { - copyClosestEquivalentTranslation(document); - } + // TODO No need for docId param since it's resource.getName() + document = + this.documentServiceImpl.saveDocument( + this.projectSlug, this.iterationSlug, resource.getName(), resource, extensions, copytrans); EntityTag etag = eTagUtils.generateETagForDocument(hProjectIteration, document.getDocId(), extensions); @@ -313,7 +297,7 @@ public Response getResource(@PathParam("id") String idNoSlash, @QueryParam("ext" String id = URIHelper.convertFromDocumentURIId(idNoSlash); HProjectIteration hProjectIteration = retrieveAndCheckIteration(false); - validateExtensions(extensions); + resourceUtils.validateExtensions(extensions); final Set extSet = new HashSet(extensions); EntityTag etag = eTagUtils.generateETagForDocument(hProjectIteration, id, extSet); @@ -379,72 +363,23 @@ public Response putResource(@PathParam("id") String idNoSlash, Resource resource log.debug("start put resource"); String id = URIHelper.convertFromDocumentURIId(idNoSlash); Response.ResponseBuilder response; - EntityTag etag = null; - boolean changed = false; HProjectIteration hProjectIteration = retrieveAndCheckIteration(true); - validateExtensions(extensions); - - log.debug("resource details: {0}", resource); + resourceUtils.validateExtensions(extensions); - HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, id); - HLocale hLocale = validateSourceLocale(resource.getLang()); - int nextDocRev; - if (document == null) - { // must be a create operation - nextDocRev = 1; - response = request.evaluatePreconditions(); - if (response != null) - { - return response.build(); - } - changed = true; - // TODO check that entity name matches id parameter - document = new HDocument(resource.getName(), resource.getContentType(), hLocale); - document.setProjectIteration(hProjectIteration); - hProjectIteration.getDocuments().put(id, document); - response = Response.created(uri.getAbsolutePath()); - } - else if (document.isObsolete()) - { // must also be a create operation - nextDocRev = document.getRevision() + 1; - response = request.evaluatePreconditions(); - if (response != null) - { - return response.build(); - } - changed = true; - document.setObsolete(false); - // not sure if this is needed - hProjectIteration.getDocuments().put(id, document); + HDocument document = this.documentDAO.getByDocIdAndIteration(hProjectIteration, id); + if( document == null || document.isObsolete() ) + { response = Response.created(uri.getAbsolutePath()); } else - { // must be an update operation - nextDocRev = document.getRevision() + 1; - etag = eTagUtils.generateETagForDocument(hProjectIteration, id, extensions); - response = request.evaluatePreconditions(etag); - if (response != null) - { - return response.build(); - } - + { response = Response.ok(); } - changed |= resourceUtils.transferFromResource(resource, document, extensions, hLocale, nextDocRev); + document = this.documentServiceImpl.saveDocument(projectSlug, iterationSlug, id, resource, extensions, copytrans); - if (changed) - { - document = documentDAO.makePersistent(document); - documentDAO.flush(); - etag = eTagUtils.generateETagForDocument(hProjectIteration, id, extensions); - } - - if (copytrans && nextDocRev == 1) - { - copyClosestEquivalentTranslation(document); - } + EntityTag etag = eTagUtils.generateETagForDocument(hProjectIteration, document.getDocId(), extensions); log.debug("put resource successfully"); return response.tag(etag).build(); @@ -600,7 +535,7 @@ public Response putResourceMeta(@PathParam("id") String idNoSlash, ResourceMeta private HProjectIteration retrieveAndCheckIteration(boolean writeOperation) { HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug); - HProject hProject = projectDAO.getBySlug(projectSlug); + HProject hProject = hProjectIteration == null ? null : hProjectIteration.getProject(); if (hProjectIteration == null) { diff --git a/server/zanata-war/src/main/java/org/zanata/rest/service/TranslatedDocResourceService.java b/server/zanata-war/src/main/java/org/zanata/rest/service/TranslatedDocResourceService.java index b99c49982e..a8ae1457da 100644 --- a/server/zanata-war/src/main/java/org/zanata/rest/service/TranslatedDocResourceService.java +++ b/server/zanata-war/src/main/java/org/zanata/rest/service/TranslatedDocResourceService.java @@ -28,7 +28,6 @@ import org.jboss.seam.annotations.security.Restrict; import org.jboss.seam.log.Log; import org.jboss.seam.log.Logging; -import org.jboss.seam.security.Identity; import org.zanata.ApplicationConfiguration; import org.zanata.common.EntityStatus; import org.zanata.common.LocaleId; @@ -80,7 +79,6 @@ import java.util.Set; import static org.zanata.rest.service.SourceDocResource.RESOURCE_SLUG_TEMPLATE; -import static org.zanata.service.impl.TranslationServiceImpl.validateExtensions; @Name("translatedDocResourceService") @Path(TranslatedDocResourceService.SERVICE_PATH) @@ -254,7 +252,7 @@ public Response getTranslations( String id = URIHelper.convertFromDocumentURIId(idNoSlash); HProjectIteration hProjectIteration = retrieveAndCheckIteration(false); - validateExtensions(extensions); + resourceUtils.validateExtensions(extensions); // TODO create valid etag EntityTag etag = eTagUtils.generateETagForDocument(hProjectIteration, id, extensions); @@ -427,7 +425,7 @@ public String apply(@Nullable TextFlowTarget from) private HProjectIteration retrieveAndCheckIteration(boolean writeOperation) { HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug); - HProject hProject = projectDAO.getBySlug(projectSlug); + HProject hProject = hProjectIteration == null ? null : hProjectIteration.getProject(); if (hProjectIteration == null) { diff --git a/server/zanata-war/src/main/java/org/zanata/service/DocumentService.java b/server/zanata-war/src/main/java/org/zanata/service/DocumentService.java new file mode 100644 index 0000000000..85c74253d6 --- /dev/null +++ b/server/zanata-war/src/main/java/org/zanata/service/DocumentService.java @@ -0,0 +1,47 @@ +/* + * 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; + +import org.zanata.model.HDocument; +import org.zanata.rest.dto.resource.Resource; + +import java.util.Set; + +/** + * @author Carlos Munoz camunoz@redhat.com + */ +public interface DocumentService +{ + /** + * Creates or Updates a document. + * + * @param projectSlug The document's project id. + * @param iterationSlug The document's project iteration id. + * @param docId The document id. + * @param sourceDoc The document contents. + * @param extensions Document extensions to save. + * @param copyTrans Whether to copy translations from other projects or not. A true value does not guarantee that + * this will happen, it is only a suggestion. + * @return The created / updated document + */ + public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, + Set extensions, boolean copyTrans ); +} diff --git a/server/zanata-war/src/main/java/org/zanata/service/SlugEntityService.java b/server/zanata-war/src/main/java/org/zanata/service/SlugEntityService.java new file mode 100644 index 0000000000..8a39fb2a44 --- /dev/null +++ b/server/zanata-war/src/main/java/org/zanata/service/SlugEntityService.java @@ -0,0 +1,41 @@ +/* + * 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; + +import org.zanata.model.SlugEntityBase; + +/** + * Provides common services related to the slug based entities ({@link org.zanata.model.SlugEntityBase}). + * + * @author Carlos Munoz camunoz@redhat.com + */ +public interface SlugEntityService +{ + /** + * Determines if a given slug is available in a class. + * + * @param slug The slug to check + * @param cls The class to verify the slug against. + * @return True if the slug is not in use by any other elements of cls. False, otherwise. + */ + boolean isSlugAvailable(String slug, Class cls); + +} diff --git a/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java b/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java index 11e8fe321b..adcfd1c926 100644 --- a/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java +++ b/server/zanata-war/src/main/java/org/zanata/service/TranslationService.java @@ -49,21 +49,6 @@ public interface TranslationService Collection translateAll(String projectSlug, String iterationSlug, String docId, LocaleId locale, TranslationsResource translations, Set extensions, MergeType mergeType); - /** - * Creates or Updates a document. - * - * @param projectSlug The document's project id. - * @param iterationSlug The document's project iteration id. - * @param docId The document id. - * @param sourceDoc The document contents. - * @param extensions Document extensions to save. - * @param copyTrans Whether to copy translations from other projects or not. A true value does not guarantee that - * this will happen, it is only a suggestion. - * @return The created / updated document - */ - public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, - Set extensions, boolean copyTrans ); - public interface TranslationResult { HTextFlow getTextFlow(); diff --git a/server/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java b/server/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java new file mode 100644 index 0000000000..ee014743b0 --- /dev/null +++ b/server/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java @@ -0,0 +1,151 @@ +/* + * 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 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.Scope; +import org.zanata.ApplicationConfiguration; +import org.zanata.dao.DocumentDAO; +import org.zanata.dao.ProjectIterationDAO; +import org.zanata.model.HDocument; +import org.zanata.model.HLocale; +import org.zanata.model.HProjectIteration; +import org.zanata.rest.dto.resource.Resource; +import org.zanata.rest.service.ResourceUtils; +import org.zanata.service.CopyTransService; +import org.zanata.service.DocumentService; +import org.zanata.service.LocaleService; + +import java.util.Set; + +/** + * Default implementation of the {@link DocumentService} business service interface. + * + * @author Carlos Munoz camunoz@redhat.com + */ +@Name("documentServiceImpl") +@AutoCreate +@Scope(ScopeType.STATELESS) +public class DocumentServiceImpl implements DocumentService +{ + @In + private ProjectIterationDAO projectIterationDAO; + + @In + private DocumentDAO documentDAO; + + @In + private LocaleService localeServiceImpl; + + @In + private CopyTransService copyTransServiceImpl; + + @In + private ResourceUtils resourceUtils; + + @In + private ApplicationConfiguration applicationConfiguration; + + + public DocumentServiceImpl() + { + } + + public DocumentServiceImpl(ProjectIterationDAO projectIterationDAO, + DocumentDAO documentDAO, + LocaleService localeService, + CopyTransService copyTransService, + ResourceUtils resourceUtils, + ApplicationConfiguration applicationConfiguration) + { + this.projectIterationDAO = projectIterationDAO; + this.documentDAO = documentDAO; + this.localeServiceImpl = localeService; + this.copyTransServiceImpl = copyTransService; + this.resourceUtils = resourceUtils; + this.applicationConfiguration = applicationConfiguration; + } + + public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, + Set extensions, boolean copyTrans ) + { + // Only active iterations allow the addition of a document + HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug); + + HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, docId); + HLocale hLocale = this.localeServiceImpl.validateSourceLocale( sourceDoc.getLang() ); + + boolean changed = false; + int nextDocRev; + if (document == null) + { // must be a create operation + nextDocRev = 1; + changed = true; + // TODO check that entity name matches id parameter + document = new HDocument(sourceDoc.getName(), sourceDoc.getContentType(), hLocale); + document.setProjectIteration(hProjectIteration); + hProjectIteration.getDocuments().put(docId, document); + } + else if (document.isObsolete()) + { // must also be a create operation + nextDocRev = document.getRevision() + 1; + changed = true; + document.setObsolete(false); + // not sure if this is needed + hProjectIteration.getDocuments().put(docId, document); + } + else + { // must be an update operation + nextDocRev = document.getRevision() + 1; + } + + changed |= resourceUtils.transferFromResource(sourceDoc, document, extensions, hLocale, nextDocRev); + + if (changed) + { + document = documentDAO.makePersistent(document); + documentDAO.flush(); + } + + if (copyTrans && nextDocRev == 1) + { + copyClosestEquivalentTranslation(document); + } + + return document; + } + + /** + * Invoke the copy trans function for a document. + * + * @param document The document to copy translations into. + */ + private void copyClosestEquivalentTranslation(HDocument document) + { + if (applicationConfiguration.getEnableCopyTrans()) + { + copyTransServiceImpl.copyTransForDocument(document); + } + } +} diff --git a/server/zanata-war/src/main/java/org/zanata/service/impl/SlugEntityServiceImpl.java b/server/zanata-war/src/main/java/org/zanata/service/impl/SlugEntityServiceImpl.java new file mode 100644 index 0000000000..2ee505ca93 --- /dev/null +++ b/server/zanata-war/src/main/java/org/zanata/service/impl/SlugEntityServiceImpl.java @@ -0,0 +1,51 @@ +/* + * 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 org.hibernate.Session; +import org.hibernate.criterion.Restrictions; +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.Scope; +import org.zanata.model.SlugEntityBase; +import org.zanata.service.SlugEntityService; + +/** + * Default implementation of the {@link org.zanata.service.SlugEntityService} interface. + * + * @author Carlos Munoz camunoz@redhat.com + */ +@Name("slugEntityServiceImpl") +@AutoCreate +@Scope(ScopeType.STATELESS) +public class SlugEntityServiceImpl implements SlugEntityService +{ + @In + private Session session; + + @Override + public boolean isSlugAvailable(String slug, Class cls) + { + return session.createCriteria(cls).add(Restrictions.eq("slug", slug)).list().size() == 0; + } +} diff --git a/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java b/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java index 63ff0ecc4b..9a773cc58d 100644 --- a/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java +++ b/server/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java @@ -18,8 +18,6 @@ import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.Collections2; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; import org.hibernate.Session; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; @@ -30,7 +28,6 @@ import org.jboss.seam.log.Log; import org.jboss.seam.log.Logging; import org.jboss.seam.security.management.JpaIdentityStore; -import org.zanata.ApplicationConfiguration; import org.zanata.common.ContentState; import org.zanata.common.EntityStatus; import org.zanata.common.LocaleId; @@ -52,12 +49,9 @@ import org.zanata.model.HProjectIteration; import org.zanata.model.HTextFlow; import org.zanata.model.HTextFlowTarget; -import org.zanata.rest.dto.extensions.ExtensionType; -import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TextFlowTarget; import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.rest.service.ResourceUtils; -import org.zanata.service.CopyTransService; import org.zanata.service.LocaleService; import org.zanata.service.TranslationService; import org.zanata.webtrans.server.TranslationWorkspaceManager; @@ -115,12 +109,6 @@ public class TranslationServiceImpl implements TranslationService @In private LocaleService localeServiceImpl; - @In - private CopyTransService copyTransServiceImpl; - - @In - private ApplicationConfiguration applicationConfiguration; - @In(value = JpaIdentityStore.AUTHENTICATED_USER, scope = ScopeType.SESSION) private HAccount authenticatedAccount; @@ -217,9 +205,13 @@ public TranslationResult translate(Long textFlowId, LocaleId localeId, ContentSt public Collection translateAll(String projectSlug, String iterationSlug, String docId, LocaleId locale, TranslationsResource translations, Set extensions, MergeType mergeType) { - HProjectIteration hProjectIteration = retrieveAndCheckIteration(projectSlug, iterationSlug, true); + HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug); + if( hProjectIteration == null ) + { + throw new ZanataServiceException("Version '" + iterationSlug + "' for project '" + projectSlug + "' "); + } - validateExtensions(extensions); + resourceUtils.validateExtensions(extensions); log.debug("pass evaluate"); HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, docId); @@ -368,56 +360,6 @@ else if (incomingTarget.getState() == ContentState.Approved) return unknownResIds; } - public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, - Set extensions, boolean copyTrans ) - { - HProjectIteration hProjectIteration = retrieveAndCheckIteration(projectSlug, iterationSlug, true); - - validateExtensions(extensions); - - HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, docId); - HLocale hLocale = this.localeServiceImpl.validateSourceLocale( sourceDoc.getLang() ); - - boolean changed = false; - int nextDocRev; - if (document == null) - { // must be a create operation - nextDocRev = 1; - changed = true; - // TODO check that entity name matches id parameter - document = new HDocument(sourceDoc.getName(), sourceDoc.getContentType(), hLocale); - document.setProjectIteration(hProjectIteration); - hProjectIteration.getDocuments().put(docId, document); - } - else if (document.isObsolete()) - { // must also be a create operation - nextDocRev = document.getRevision() + 1; - changed = true; - document.setObsolete(false); - // not sure if this is needed - hProjectIteration.getDocuments().put(docId, document); - } - else - { // must be an update operation - nextDocRev = document.getRevision() + 1; - } - - changed |= resourceUtils.transferFromResource(sourceDoc, document, extensions, hLocale, nextDocRev); - - if (changed) - { - document = documentDAO.makePersistent(document); - documentDAO.flush(); - } - - if (copyTrans && nextDocRev == 1) - { - copyClosestEquivalentTranslation(document); - } - - return document; - } - private void determineContentState(Long textFlowId, ContentState stateToSet, List contentToSave, HTextFlowTarget target) { Collection emptyContents = getEmptyContents(contentToSave); @@ -450,36 +392,6 @@ public boolean apply(@Nullable String input) }); } - private HProjectIteration retrieveAndCheckIteration(String projectSlug, String iterationSlug, boolean writeOperation) - { - HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug); - HProject hProject = projectDAO.getBySlug(projectSlug); - - if (hProjectIteration == null) - { - throw new ZanataServiceException("Project Iteration '" + projectSlug + ":" + iterationSlug + "' not found.", 404); - } - else if (hProjectIteration.getStatus().equals(EntityStatus.OBSOLETE) || hProject.getStatus().equals(EntityStatus.OBSOLETE)) - { - throw new ZanataServiceException("Project Iteration '" + projectSlug + ":" + iterationSlug + "' not found.", 404); - } - else if (writeOperation) - { - if (hProjectIteration.getStatus().equals(EntityStatus.READONLY) || hProject.getStatus().equals(EntityStatus.READONLY)) - { - throw new ZanataServiceException("Project Iteration '" + projectSlug + ":" + iterationSlug + "' is read-only.", 404); - } - else - { - return hProjectIteration; - } - } - else - { - return hProjectIteration; - } - } - private void checkTargetState(String resId, ContentState state, List contents) { switch (state) @@ -511,39 +423,6 @@ private void checkTargetState(String resId, ContentState state, List con } } - - /** - * Ensures that any extensions sent with the current query are valid for this - * context. - * - * @param requestedExt Extensions to be validated - * @throws ZanataServiceException if any unsupported extensions are present - */ - public static void validateExtensions(Set requestedExt) - { - Set validExtensions = ExtensionType.asStringSet(); - - if(!CollectionUtils.isSubCollection(requestedExt, validExtensions)) - { - @SuppressWarnings("unchecked") - Collection invalidExtensions = CollectionUtils.subtract(requestedExt, validExtensions); - throw new ZanataServiceException("Unsupported Extensions within this context: " + StringUtils.join(invalidExtensions, ","), 400); - } - } - - /** - * Invoke the copy trans function for a document. - * - * @param document The document to copy translations into. - */ - private void copyClosestEquivalentTranslation(HDocument document) - { - if (applicationConfiguration.getEnableCopyTrans()) - { - copyTransServiceImpl.copyTransForDocument(document); - } - } - public static class TranslationResultImpl implements TranslationResult { private HTextFlow textFlow; diff --git a/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java b/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java index 0117d81cbd..6634b3937b 100644 --- a/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java +++ b/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java @@ -56,8 +56,10 @@ import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.security.ZanataIdentity; import org.zanata.service.CopyTransService; +import org.zanata.service.DocumentService; import org.zanata.service.TranslationService; import org.zanata.service.impl.CopyTransServiceImpl; +import org.zanata.service.impl.DocumentServiceImpl; import org.zanata.service.impl.LocaleServiceImpl; import org.zanata.service.impl.TranslationServiceImpl; import org.zanata.util.HashUtil; @@ -130,6 +132,7 @@ public class TranslationResourceRestTest extends ZanataRestTest LocaleServiceImpl localeService; TranslationService translationService; CopyTransService copyTransService; + DocumentService documentService; Events events; ISourceDocResource sourceDocResource; @@ -204,13 +207,22 @@ public boolean tryLogin() resourceUtils ); + documentService = new DocumentServiceImpl( + projectIterationDAO, + documentDAO, + localeService, + copyTransService, + resourceUtils, + applicationConfiguration + ); + // @formatter:off SourceDocResourceService sourceDocResourceService = new SourceDocResourceService( - projectDAO, projectIterationDAO, documentDAO, localeService, copyTransService, + documentService, applicationConfiguration, resourceUtils, eTagUtils From 2e0811cfedb7a196f72f372229570fccdde60381 Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Fri, 4 May 2012 10:38:34 +1000 Subject: [PATCH 3/5] Add SeamAutowire test helper. SeamAutowire is a helper class that simulates a Seam environment and component injection. --- server/zanata-war/pom.xml | 2 +- .../org/zanata/seam/AutowireComponent.java | 57 +++ .../java/org/zanata/seam/SeamAutowire.java | 373 ++++++++++++++++++ .../org/zanata/seam/SeamAutowireTest.java | 79 ++++ 4 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 server/zanata-war/src/test/java/org/zanata/seam/AutowireComponent.java create mode 100644 server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java create mode 100644 server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java diff --git a/server/zanata-war/pom.xml b/server/zanata-war/pom.xml index 4084c63392..406ac51515 100644 --- a/server/zanata-war/pom.xml +++ b/server/zanata-war/pom.xml @@ -853,7 +853,7 @@ org.zanata zanata-api-compat - 1.2-SNAPSHOT + 1.1 test v1.5.0 diff --git a/server/zanata-war/src/test/java/org/zanata/seam/AutowireComponent.java b/server/zanata-war/src/test/java/org/zanata/seam/AutowireComponent.java new file mode 100644 index 0000000000..48ce372cb2 --- /dev/null +++ b/server/zanata-war/src/test/java/org/zanata/seam/AutowireComponent.java @@ -0,0 +1,57 @@ +/* + * 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.seam; + +import org.jboss.seam.ScopeType; + +/** + * Replacement class for Seam's {@link org.jboss.seam.Component}. + * Tests that use the {@link SeamAutowire} class will use this class instead of + * Seam's one to request components. + * + * @author Carlos Munoz camunoz@redhat.com + */ +public class AutowireComponent +{ + private static SeamAutowire instance; + + public static void setInstance(SeamAutowire instance) + { + AutowireComponent.instance = instance; + } + + public static Object getInstance(String name, boolean create, boolean allowAutocreation) + { + return SeamAutowire.instance().getComponent(name); + } + + public static Object getInstance(String name, ScopeType scope, boolean create, boolean allowAutocreation) + { + return SeamAutowire.instance().getComponent(name); + } + + public static Object getInstance(String name, boolean create, boolean allowAutoCreation, Object result) + { + return SeamAutowire.instance().getComponent(name); + } + + +} diff --git a/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java new file mode 100644 index 0000000000..4014516ebd --- /dev/null +++ b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java @@ -0,0 +1,373 @@ +/* + * 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.seam; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.NotFoundException; +import org.apache.commons.lang.ArrayUtils; +import org.jboss.seam.Component; +import org.jboss.seam.annotations.In; +import org.jboss.seam.annotations.Logger; +import org.jboss.seam.log.Logging; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Helps with Auto-wiring of Seam components for integrated tests without the need for a full Seam + * environment. + * It's a singleton class that upon first use will change the way Seam's {@link org.jboss.seam.Component} class + * works by returning its own auto-wired components. + * + * Supports components injected using: + * {@link In} + * {@link Logger} + * {@link org.jboss.seam.Component#getInstance(String)} and similar methods... + * and that have no-arg constructors + * + * @author Carlos Munoz camunoz@redhat.com + */ +public class SeamAutowire +{ + private static SeamAutowire instance; + + private Map namedComponents = new HashMap(); + + //private Map classComponents = new HashMap(); + + private boolean ignoreNonResolvable; + + + protected SeamAutowire() + { + } + + public static final SeamAutowire instance() + { + if(instance == null) + { + instance = new SeamAutowire(); + instance.rewireSeamComponents(); + } + return instance; + } + + public SeamAutowire reset() + { + this.ignoreNonResolvable = false; + this.namedComponents.clear(); + return this; + } + + public SeamAutowire use(String name, Object component) + { + this.addComponentInstance(name, component); + return this; + } + + public SeamAutowire ignoreNonResolvable() + { + this.ignoreNonResolvable = true; + return this; + } + + public Object getComponent(String name) + { + if( this.namedComponents.containsKey(name) ) + { + return this.namedComponents.get(name); + } + return null; + } + + public T autowire(Class componentClass) + { + // Create a new component instance (must have a no-arg constructor per Seam spec) + T component; + try + { + component = componentClass.newInstance(); + } + catch (InstantiationException e) + { + throw new RuntimeException("Could not auto-wire component of type " + componentClass.getName(), e); + } + catch (IllegalAccessException e) + { + throw new RuntimeException("Could not auto-wire component of type " + componentClass.getName(), e); + } + + return this.autowire(component); + } + + public T autowire(T component) + { + Class componentClass = (Class)component.getClass(); + + for( Field compField : getAllComponentFields(component) ) + { + compField.setAccessible(true); + + // Other annotated component + if( compField.getAnnotation(In.class) != null ) + { + Object fieldVal = null; + String compName = getComponentName(compField); + + // autowire the component if not done yet + if( !namedComponents.containsKey(compName) ) + { + try + { + Object newComponent = autowire(compField.getType()); + this.addComponentInstance(compName, newComponent); + } + catch (RuntimeException e) + { + if( ignoreNonResolvable ) + { + // TODO warn + } + else + { + throw e; + } + } + } + + fieldVal = namedComponents.get( compName ); + + try + { + compField.set( component, fieldVal); + } + catch (IllegalAccessException e) + { + throw new RuntimeException("Could not auto-wire field " + compField.getName() + + " in component of type " + componentClass.getName(), e); + } + } + // Logs + else if( compField.getAnnotation(Logger.class) != null ) + { + try + { + compField.set( component, Logging.getLog(compField.getType())); + } + catch (IllegalAccessException e) + { + throw new RuntimeException("Could not auto-wire field " + compField.getName() + + " in component of type " + componentClass.getName(), e); + } + } + } + + // Resolve injected components using methods + for( Method compMethod : getAllComponentMethods(component) ) + { + compMethod.setAccessible(true); + + // Other annotated component + if( compMethod.getAnnotation(In.class) != null ) + { + Object fieldVal = null; + String compName = getComponentName(compMethod); + + // autowire the component if not done yet + if( !namedComponents.containsKey(compName) ) + { + try + { + Object newComponent = autowire(compMethod.getParameterTypes()[0]); + this.addComponentInstance(compName, newComponent); + } + catch (RuntimeException e) + { + if( ignoreNonResolvable ) + { + // TODO warn + } + else + { + throw e; + } + } + } + + fieldVal = namedComponents.get(compName); + + try + { + compMethod.invoke(component, fieldVal); + } + catch (InvocationTargetException e) + { + throw new RuntimeException("Could not auto-wire field " + compMethod.getName() + + " in component of type " + componentClass.getName(), e); + } + catch (IllegalAccessException e) + { + throw new RuntimeException("Could not auto-wire field " + compMethod.getName() + + " in component of type " + componentClass.getName(), e); + } + } + // Logs + else if( compMethod.getAnnotation(Logger.class) != null ) + { + try + { + compMethod.invoke( component, Logging.getLog(compMethod.getParameterTypes()[0])); + } + catch(InvocationTargetException e) + { + throw new RuntimeException("Could not auto-wire field " + compMethod.getName() + + " in component of type " + componentClass.getName(), e); + } + catch (IllegalAccessException e) + { + throw new RuntimeException("Could not auto-wire field " + compMethod.getName() + + " in component of type " + componentClass.getName(), e); + } + } + } + + return component; + } + + private void addComponentInstance(String name, Object compInst) + { + this.namedComponents.put(name, compInst); + //this.classComponents.put(compInst.getClass(), compInst); + } + + private void rewireSeamComponents() + { + try + { + ClassPool pool = ClassPool.getDefault(); + CtClass cls = pool.get("org.jboss.seam.Component"); + + // Commonly used CtClasses + final CtClass stringCls = pool.get("java.lang.String"); + final CtClass booleanCls = pool.get("boolean"); + final CtClass objectCls = pool.get("java.lang.Object"); + final CtClass scopeTypeCls = pool.get("org.jboss.seam.ScopeType"); + + // Replace Component's method bodies with the ones in AutowireComponent + CtMethod methodToReplace = cls.getDeclaredMethod("getInstance", new CtClass[]{stringCls, booleanCls, booleanCls}); + methodToReplace.setBody( + pool.get(AutowireComponent.class.getName()).getDeclaredMethod("getInstance", new CtClass[]{stringCls, booleanCls, booleanCls}), + null); + + methodToReplace = cls.getDeclaredMethod("getInstance", new CtClass[]{stringCls, scopeTypeCls, booleanCls, booleanCls}); + methodToReplace.setBody( + pool.get(AutowireComponent.class.getName()).getDeclaredMethod("getInstance", new CtClass[]{stringCls, scopeTypeCls, booleanCls, booleanCls}), + null); + + methodToReplace = cls.getDeclaredMethod("getInstance", new CtClass[]{stringCls, booleanCls, booleanCls, objectCls}); + methodToReplace.setBody( + pool.get(AutowireComponent.class.getName()).getDeclaredMethod("getInstance", new CtClass[]{stringCls, booleanCls, booleanCls, objectCls}), + null); + + cls.toClass(); + } + catch (NotFoundException e) + { + throw new RuntimeException("Problem rewiring Seam's Component class", e); + } + catch (CannotCompileException e) + { + throw new RuntimeException("Problem rewiring Seam's Component class", e); + } + + } + + private static Field[] getAllComponentFields(Object component) + { + Field[] fields = component.getClass().getDeclaredFields(); + Class superClass = component.getClass().getSuperclass(); + + while(superClass != null) + { + fields = (Field[])ArrayUtils.addAll(fields, superClass.getDeclaredFields()); + superClass = superClass.getSuperclass(); + } + + return fields; + } + + private static Method[] getAllComponentMethods(Object component) + { + Method[] methods = component.getClass().getDeclaredMethods(); + Class superClass = component.getClass().getSuperclass(); + + while(superClass != null) + { + methods = (Method[])ArrayUtils.addAll(methods, superClass.getDeclaredMethods()); + superClass = superClass.getSuperclass(); + } + + return methods; + } + + private static String getComponentName( Field field ) + { + In inAnnot = field.getAnnotation(In.class); + if( inAnnot != null ) + { + if( inAnnot.value().trim().isEmpty() ) + { + return field.getName(); + } + else + { + return inAnnot.value(); + } + } + return null; + } + + private static String getComponentName( Method method ) + { + In inAnnot = method.getAnnotation(In.class); + if( inAnnot != null ) + { + if( inAnnot.value().trim().isEmpty() ) + { + // assume it's a setter + String name = method.getName().substring(3); + name = name.substring(0,1).toLowerCase() + name.substring(1); + return name; + } + else + { + return inAnnot.value(); + } + } + return null; + } +} diff --git a/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java new file mode 100644 index 0000000000..9b385195a8 --- /dev/null +++ b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java @@ -0,0 +1,79 @@ +/* + * 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.seam; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.jboss.seam.Component; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; +import org.zanata.ZanataDbunitJpaTest; +import org.zanata.dao.ProjectDAO; + +/** + * Tests for the {@link SeamAutowire} component. + * Also useful as a template for other Autowire tests. + * + * @author Carlos Munoz camunoz@redhat.com + */ +public class SeamAutowireTest extends ZanataDbunitJpaTest +{ + @Override + protected void prepareDBUnitOperations() + { + } + + @BeforeTest + public void resetSeamAutowire() + { + SeamAutowire.instance().reset(); + } + + @Test + public void autowireSession() + { + ProjectDAO dao = SeamAutowire.instance().ignoreNonResolvable().use("session", getSession()).autowire(ProjectDAO.class); + + int t = dao.getTotalProjectCount(); + System.out.println("Total Projects: " + t); + } + + @Test + public void autowireProvided() + { + ProjectDAO dao = new ProjectDAO(); + dao = SeamAutowire.instance().ignoreNonResolvable().use("session", getSession()).autowire(dao); + + int t = dao.getTotalProjectCount(); + System.out.println("Total Projects: " + t); + } + + @Test + public void testComponentInvocation() + { + SeamAutowire.instance().use("component", "This is the component!"); + + String val = (String)Component.getInstance("component"); + + MatcherAssert.assertThat(val, Matchers.is("This is the component!")); + } +} From a6ba7c0b290df846802f388337fd941ff48df4e6 Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Fri, 4 May 2012 15:22:32 +1000 Subject: [PATCH 4/5] First Rest test converted to use SeamAutowire. --- .../server/rpc/UpdateTransUnitHandler.java | 2 +- .../service/TranslationResourceRestTest.java | 149 ++++-------------- .../java/org/zanata/seam/SeamAutowire.java | 145 ++++++++++++++++- .../org/zanata/seam/SeamAutowireTest.java | 11 ++ 4 files changed, 184 insertions(+), 123 deletions(-) diff --git a/server/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/UpdateTransUnitHandler.java b/server/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/UpdateTransUnitHandler.java index 836e483e49..0e28e3d149 100644 --- a/server/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/UpdateTransUnitHandler.java +++ b/server/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/UpdateTransUnitHandler.java @@ -141,7 +141,7 @@ public UpdateTransUnitResult execute(UpdateTransUnit action, ExecutionContext co } catch (Exception e) { - throw new ActionException(e.getMessage()); + throw new ActionException(e); } HTextFlow hTextFlow = translationResult.getTextFlow(); diff --git a/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java b/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java index 6634b3937b..7d25529f72 100644 --- a/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java +++ b/server/zanata-war/src/test/java/org/zanata/rest/service/TranslationResourceRestTest.java @@ -11,6 +11,7 @@ import org.jboss.seam.core.Events; import org.jboss.seam.security.Credentials; import org.jboss.seam.security.Identity; +import org.jboss.seam.security.management.JpaIdentityStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.BeforeClass; @@ -54,9 +55,11 @@ import org.zanata.rest.dto.resource.TextFlow; import org.zanata.rest.dto.resource.TextFlowTarget; import org.zanata.rest.dto.resource.TranslationsResource; +import org.zanata.seam.SeamAutowire; import org.zanata.security.ZanataIdentity; import org.zanata.service.CopyTransService; import org.zanata.service.DocumentService; +import org.zanata.service.LocaleService; import org.zanata.service.TranslationService; import org.zanata.service.impl.CopyTransServiceImpl; import org.zanata.service.impl.DocumentServiceImpl; @@ -110,6 +113,8 @@ public class TranslationResourceRestTest extends ZanataRestTest private static final String DOC2_NAME = "test.properties"; private static final String DOC1_NAME = "foo.properties"; + private final SeamAutowire seam = SeamAutowire.instance(); + StringSet extGettextComment = new StringSet("gettext;comment"); StringSet extComment = new StringSet("comment"); @@ -117,23 +122,7 @@ public class TranslationResourceRestTest extends ZanataRestTest ZanataIdentity mockIdentity = mockControl.createMock(ZanataIdentity.class); TranslationWorkspaceManager transWorspaceManager = mockControl.createMock(TranslationWorkspaceManager.class); - ApplicationConfiguration applicationConfiguration; - ProjectIterationDAO projectIterationDAO; - DocumentDAO documentDAO; - TextFlowDAO textFlowDAO; - TextFlowTargetDAO textFlowTargetDAO; - ResourceUtils resourceUtils; - Identity identity; - ETagUtils eTagUtils; - PersonDAO personDAO; - AccountDAO accountDAO; - TextFlowTargetHistoryDAO textFlowTargetHistoryDAO; - ProjectDAO projectDAO; - LocaleServiceImpl localeService; TranslationService translationService; - CopyTransService copyTransService; - DocumentService documentService; - Events events; ISourceDocResource sourceDocResource; ITranslatedDocResource transResource; @@ -165,83 +154,20 @@ protected void prepareDBUnitOperations() @Override protected void prepareResources() { - this.applicationConfiguration = new ApplicationConfiguration(true); - this.projectIterationDAO = new ProjectIterationDAO(getSession()); - this.projectDAO = new ProjectDAO(getSession()); - this.documentDAO = new DocumentDAO(getSession()); - this.textFlowDAO = new TextFlowDAO(getSession()); - this.textFlowTargetDAO = new TextFlowTargetDAO(getSession()); - this.resourceUtils = new ResourceUtils(); - resourceUtils.create(); - this.identity = new Identity() - { - @Override - public boolean tryLogin() - { - return true; - } - }; - this.eTagUtils = new ETagUtils(getSession(), documentDAO); - this.personDAO = new PersonDAO(getSession()); - this.accountDAO = new AccountDAO(getSession()); - this.textFlowTargetHistoryDAO = new TextFlowTargetHistoryDAO(getSession()); - - LocaleDAO localeDAO = new LocaleDAO(getSession()); - projectDAO = new ProjectDAO(getSession()); - this.localeService = new LocaleServiceImpl(localeDAO, projectDAO, projectIterationDAO, personDAO); - localeService.setLocaleDAO(localeDAO); - - copyTransService = new CopyTransServiceImpl(localeService, textFlowTargetDAO, documentDAO); - translationService = new TranslationServiceImpl( - getSession(), - projectDAO, - transWorspaceManager, - localeService, - this.accountDAO.getByUsername("admin"), - projectIterationDAO, - documentDAO, - personDAO, - textFlowDAO, - textFlowTargetDAO, - textFlowTargetHistoryDAO, - resourceUtils - ); - - documentService = new DocumentServiceImpl( - projectIterationDAO, - documentDAO, - localeService, - copyTransService, - resourceUtils, - applicationConfiguration - ); - - // @formatter:off - SourceDocResourceService sourceDocResourceService = new SourceDocResourceService( - projectIterationDAO, - documentDAO, - localeService, - copyTransService, - documentService, - applicationConfiguration, - resourceUtils, - eTagUtils - ); - - TranslatedDocResourceService translatedDocResourceService = new TranslatedDocResourceService( - applicationConfiguration, - projectIterationDAO, - projectDAO, - documentDAO, - textFlowTargetDAO, - resourceUtils, - mockIdentity, - eTagUtils, - localeService, - copyTransService, - translationService - ); - // @formatter:on + seam.reset(); + seam.ignoreNonResolvable() + .use("session", getSession()) + .use("applicationConfiguration", new ApplicationConfiguration(true)) + .use("identity", mockIdentity) + .use("translationWorkspaceManager", transWorspaceManager) + .useImpl(CopyTransServiceImpl.class) + .useImpl(TranslationServiceImpl.class) + .useImpl(LocaleServiceImpl.class) + .useImpl(DocumentServiceImpl.class) + .useImpl(ResourceUtils.class); + + TranslatedDocResourceService translatedDocResourceService = seam.autowire(TranslatedDocResourceService.class); + SourceDocResourceService sourceDocResourceService = seam.autowire(SourceDocResourceService.class); resources.add(sourceDocResourceService); resources.add(translatedDocResourceService); @@ -984,6 +910,8 @@ public void headersAfterWebtransEdit() throws Exception super.newSession(); + AccountDAO accountDAO = seam.autowire(AccountDAO.class); + // Translator HAccount translator = accountDAO.getByUsername("demo"); @@ -1053,43 +981,34 @@ private void simulateWebEditorTranslation(String projectSlug, String iterationSl Credentials mockCredentials = new Credentials(); mockCredentials.setInitialized(true); mockCredentials.setUsername( translator.getUsername() ); - + + // Set mock expectations - expect( transWorkerManager.getOrRegisterWorkspace( anyObject(WorkspaceId.class) ) ).andReturn( transWorkspace ).anyTimes(); + expect(transWorkerManager.getOrRegisterWorkspace(anyObject(WorkspaceId.class))).andReturn( transWorkspace ).anyTimes(); expect( mockIdentity.getCredentials() ).andReturn( mockCredentials ); expect( transWorkspace.getWorkspaceContext() ).andReturn( workspaceContext ); mockIdentity.checkLoggedIn(); - expectLastCall(); + expectLastCall(); mockIdentity.checkPermission(anyObject(String.class), anyObject(HLocale.class), anyObject(HProject.class)); expectLastCall(); transWorkspace.publish(anyObject(SessionEventData.class)); expectLastCall(); mockControl.replay(); - translationService = new TranslationServiceImpl( - getSession(), - projectDAO, - transWorspaceManager, - localeService, - translator, - projectIterationDAO, - documentDAO, - personDAO, - textFlowDAO, - textFlowTargetDAO, - textFlowTargetHistoryDAO, - resourceUtils - ); + this.prepareResources(); // Reset Seam to simulate separate translation + seam.use(JpaIdentityStore.AUTHENTICATED_USER, translator); // use a given authenticated account + + translationService = seam.autowire(TranslationServiceImpl.class); // @formatter:off UpdateTransUnitHandler transUnitHandler = new UpdateTransUnitHandler( mockIdentity, - projectDAO, - textFlowTargetHistoryDAO, + seam.autowire(ProjectDAO.class), + seam.autowire(TextFlowTargetHistoryDAO.class), transWorkerManager, - localeService, + seam.autowire(LocaleServiceImpl.class), translator, - translationService); + seam.autowire(TranslationServiceImpl.class)); // @formatter:on // Translation unit id to update @@ -1465,6 +1384,7 @@ private void expectTarget2(TranslationsResource target2) private void verifyObsoleteDocument(final String docID) throws Exception { + ProjectIterationDAO projectIterationDAO = seam.autowire(ProjectIterationDAO.class); HProjectIteration iteration = projectIterationDAO.getBySlug(projectSlug, iter); Map allDocuments = iteration.getAllDocuments(); HDocument hDocument = allDocuments.get(docID); @@ -1475,6 +1395,7 @@ private void verifyObsoleteDocument(final String docID) throws Exception private void verifyObsoleteResource(final String docID, final String resourceID) throws Exception { + ProjectIterationDAO projectIterationDAO = seam.autowire(ProjectIterationDAO.class); HProjectIteration iteration = projectIterationDAO.getBySlug(projectSlug, iter); Map allDocuments = iteration.getAllDocuments(); HDocument hDocument = allDocuments.get(docID); diff --git a/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java index 4014516ebd..504671e76c 100644 --- a/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java +++ b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowire.java @@ -26,16 +26,18 @@ import javassist.CtMethod; import javassist.NotFoundException; import org.apache.commons.lang.ArrayUtils; -import org.jboss.seam.Component; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; import org.jboss.seam.log.Logging; +import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** * Helps with Auto-wiring of Seam components for integrated tests without the need for a full Seam @@ -53,10 +55,14 @@ */ public class SeamAutowire { + private static final org.slf4j.Logger log = LoggerFactory.getLogger(SeamAutowire.class); + private static SeamAutowire instance; private Map namedComponents = new HashMap(); + private Map, Class> componentImpls = new HashMap, Class>(); + //private Map classComponents = new HashMap(); private boolean ignoreNonResolvable; @@ -66,16 +72,24 @@ protected SeamAutowire() { } + /** + * Initializes and returns the SeamAutowire instance. + * + * @return The Singleton instance of the SeamAutowire class. + */ public static final SeamAutowire instance() { if(instance == null) { instance = new SeamAutowire(); - instance.rewireSeamComponents(); + instance.rewireSeamComponentClass(); } return instance; } + /** + * Clears out any components and returns to it's initial value. + */ public SeamAutowire reset() { this.ignoreNonResolvable = false; @@ -83,18 +97,53 @@ public SeamAutowire reset() return this; } + /** + * Indicates a specific instance of a component to use. + * + * @param name The name of the component. When another component injects using @In(value = "name") or + * @In varName, the provided component will be used. + * @param component The component instance to use under the provided name. + */ public SeamAutowire use(String name, Object component) { this.addComponentInstance(name, component); return this; } + /** + * Registers an implementation to use for components. This method is provided just in case some components are + * inject via interfaces. + * + * @param cls The class to register. + */ + public SeamAutowire useImpl(Class cls) + { + if( cls.isInterface() ) + { + throw new RuntimeException("Class " + cls.getName() + " is an interface."); + } + this.registerInterfaces(cls); + + return this; + } + + /** + * Indicates that a warning should be logged if for some reason a component cannot be resolved. Otherwise, an + * exception will be thrown. + */ public SeamAutowire ignoreNonResolvable() { this.ignoreNonResolvable = true; return this; } + /** + * Returns a component by name. + * + * @param name Component's name. + * @return The component registered under the provided name, or null if such a component has not been auto wired + * or cannot be resolved otherwise. + */ public Object getComponent(String name) { if( this.namedComponents.containsKey(name) ) @@ -104,10 +153,23 @@ public Object getComponent(String name) return null; } + /** + * Autowires and returns the component instance for the provided class. + * + * @param componentClass The component class to autowire. + * @return The autowired component. + */ public T autowire(Class componentClass) { // Create a new component instance (must have a no-arg constructor per Seam spec) T component; + + // If the component type is an interface, try to find a declared implementation + if( componentClass.isInterface() && this.componentImpls.containsKey(componentClass) ) + { + componentClass = (Class)this.componentImpls.get(componentClass); + } + try { component = componentClass.newInstance(); @@ -124,10 +186,21 @@ public T autowire(Class componentClass) return this.autowire(component); } + /** + * Autowires a component instance. The provided instance of the component will be autowired instead of creating a + * new one. + * + * @param component The component instance to autowire. + * @param + * @return Returns component. + */ public T autowire(T component) { Class componentClass = (Class)component.getClass(); + // Register all interfaces for this class + this.registerInterfaces(componentClass); + for( Field compField : getAllComponentFields(component) ) { compField.setAccessible(true); @@ -137,20 +210,21 @@ public T autowire(T component) { Object fieldVal = null; String compName = getComponentName(compField); + Class compType = compField.getType(); // autowire the component if not done yet if( !namedComponents.containsKey(compName) ) { try { - Object newComponent = autowire(compField.getType()); + Object newComponent = autowire(compType); this.addComponentInstance(compName, newComponent); } catch (RuntimeException e) { if( ignoreNonResolvable ) { - // TODO warn + log.warn("Could not resolve component of type: " + compType); } else { @@ -196,20 +270,21 @@ else if( compField.getAnnotation(Logger.class) != null ) { Object fieldVal = null; String compName = getComponentName(compMethod); + Class compType = compMethod.getParameterTypes()[0]; // autowire the component if not done yet if( !namedComponents.containsKey(compName) ) { try { - Object newComponent = autowire(compMethod.getParameterTypes()[0]); + Object newComponent = autowire(compType); this.addComponentInstance(compName, newComponent); } catch (RuntimeException e) { if( ignoreNonResolvable ) { - // TODO warn + log.warn("Could not resolve component of type: " + compType); } else { @@ -255,16 +330,18 @@ else if( compMethod.getAnnotation(Logger.class) != null ) } } + // call post constructor + invokePostConstructMethod(component); + return component; } private void addComponentInstance(String name, Object compInst) { this.namedComponents.put(name, compInst); - //this.classComponents.put(compInst.getClass(), compInst); } - private void rewireSeamComponents() + private void rewireSeamComponentClass() { try { @@ -370,4 +447,56 @@ private static String getComponentName( Method method ) } return null; } + + private void registerInterfaces(Class cls) + { + if( !cls.isInterface() ) + { + // register all interfaces registered by this component + for (Class iface : getAllInterfaces(cls)) + { + this.componentImpls.put(iface, cls); + } + } + } + + private static Set> getAllInterfaces(Class cls) + { + Set> interfaces = new HashSet>(); + + for( Class superClass : cls.getInterfaces() ) + { + interfaces.add(superClass); + interfaces.addAll( getAllInterfaces(superClass) ); + } + + return interfaces; + } + + private static void invokePostConstructMethod(Object component) + { + Class compClass = component.getClass(); + + for( Method m : compClass.getDeclaredMethods() ) + { + // Call the first Post Constructor found. Per the spec, there should be only one + if( m.getAnnotation(javax.annotation.PostConstruct.class) != null + || m.getAnnotation(org.jboss.seam.annotations.intercept.PostConstruct.class) != null ) + { + try + { + m.invoke(component, null); // there should be no params + } + catch (IllegalAccessException e) + { + throw new RuntimeException("Error invoking Post construct method in component of class: " + compClass.getName(), e); + } + catch (InvocationTargetException e) + { + throw new RuntimeException("Error invoking Post construct method in component of class: " + compClass.getName(), e); + } + } + } + } + } diff --git a/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java index 9b385195a8..5826cc1edb 100644 --- a/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java +++ b/server/zanata-war/src/test/java/org/zanata/seam/SeamAutowireTest.java @@ -28,6 +28,8 @@ import org.testng.annotations.Test; import org.zanata.ZanataDbunitJpaTest; import org.zanata.dao.ProjectDAO; +import org.zanata.service.CopyTransService; +import org.zanata.service.impl.CopyTransServiceImpl; /** * Tests for the {@link SeamAutowire} component. @@ -67,6 +69,15 @@ public void autowireProvided() System.out.println("Total Projects: " + t); } + @Test + public void interfaceImplementations() + { + SeamAutowire.instance().ignoreNonResolvable().autowire(CopyTransServiceImpl.class); + + CopyTransService copyTrans = SeamAutowire.instance().autowire(CopyTransService.class); + MatcherAssert.assertThat(copyTrans, Matchers.notNullValue()); + } + @Test public void testComponentInvocation() { From ee9a13467a10641f4240c35ac8853b95e4268a74 Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Fri, 4 May 2012 15:39:37 +1000 Subject: [PATCH 5/5] Migrate all other Rest tests to SeamAutowire. --- .../org/zanata/rest/service/GlossaryRestTest.java | 14 ++++++++------ .../rest/service/ProjectIterationRestTest.java | 13 +++++++------ .../org/zanata/rest/service/ProjectRestTest.java | 12 +++++++----- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/server/zanata-war/src/test/java/org/zanata/rest/service/GlossaryRestTest.java b/server/zanata-war/src/test/java/org/zanata/rest/service/GlossaryRestTest.java index 7bcf13e765..8cbf68eefb 100644 --- a/server/zanata-war/src/test/java/org/zanata/rest/service/GlossaryRestTest.java +++ b/server/zanata-war/src/test/java/org/zanata/rest/service/GlossaryRestTest.java @@ -26,6 +26,7 @@ import org.zanata.rest.dto.Glossary; import org.zanata.rest.dto.GlossaryEntry; import org.zanata.rest.dto.GlossaryTerm; +import org.zanata.seam.SeamAutowire; import org.zanata.service.impl.LocaleServiceImpl; public class GlossaryRestTest extends ZanataRestTest @@ -35,6 +36,7 @@ public class GlossaryRestTest extends ZanataRestTest IMocksControl mockControl = EasyMock.createControl(); Identity mockIdentity = mockControl.createMock(Identity.class); IGlossaryResource glossaryService; + SeamAutowire seam = SeamAutowire.instance(); @BeforeClass void beforeClass() @@ -65,13 +67,13 @@ protected void prepareDBUnitOperations() @Override protected void prepareResources() { - GlossaryDAO glossaryDAO = new GlossaryDAO(getSession()); + seam.reset(); + seam.ignoreNonResolvable() + .use("session", getSession()) + .use("identity", mockIdentity) + .useImpl(LocaleServiceImpl.class); - LocaleServiceImpl localeService = new LocaleServiceImpl(); - LocaleDAO localeDAO = new LocaleDAO(getSession()); - localeService.setLocaleDAO(localeDAO); - - GlossaryService glossaryService = new GlossaryService(glossaryDAO, mockIdentity, localeService); + GlossaryService glossaryService = seam.autowire(GlossaryService.class); resources.add(glossaryService); } diff --git a/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectIterationRestTest.java b/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectIterationRestTest.java index eff8f6eecd..015449732e 100644 --- a/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectIterationRestTest.java +++ b/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectIterationRestTest.java @@ -23,6 +23,7 @@ import org.zanata.dao.ProjectIterationDAO; import org.zanata.rest.client.IProjectIterationResource; import org.zanata.rest.dto.ProjectIteration; +import org.zanata.seam.SeamAutowire; public class ProjectIterationRestTest extends ZanataRestTest { @@ -30,6 +31,7 @@ public class ProjectIterationRestTest extends ZanataRestTest private final String RESOURCE_PATH = "/projects/p/sample-project/iterations/i/"; IMocksControl mockControl = EasyMock.createControl(); Identity mockIdentity = mockControl.createMock(Identity.class); + SeamAutowire seam = SeamAutowire.instance(); @BeforeClass void beforeClass() @@ -52,13 +54,12 @@ protected void prepareDBUnitOperations() @Override protected void prepareResources() { + seam.reset(); + seam.ignoreNonResolvable() + .use("session", getSession()) + .use("identity", mockIdentity); - ProjectDAO projectDAO = new ProjectDAO(getSession()); - ProjectIterationDAO projectIterationDAO = new ProjectIterationDAO(getSession()); - DocumentDAO documentDAO = new DocumentDAO(getSession()); - ETagUtils eTagUtils = new ETagUtils(getSession(), documentDAO); - - ProjectIterationService projectIterationService = new ProjectIterationService(projectDAO, projectIterationDAO, mockIdentity, eTagUtils); + ProjectIterationService projectIterationService = seam.autowire(ProjectIterationService.class); resources.add(projectIterationService); } diff --git a/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectRestTest.java b/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectRestTest.java index 0d8977d749..b0cf217a86 100644 --- a/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectRestTest.java +++ b/server/zanata-war/src/test/java/org/zanata/rest/service/ProjectRestTest.java @@ -28,6 +28,7 @@ import org.zanata.rest.client.IProjectResource; import org.zanata.rest.dto.Project; import org.zanata.rest.dto.ProjectType; +import org.zanata.seam.SeamAutowire; public class ProjectRestTest extends ZanataRestTest { @@ -35,6 +36,7 @@ public class ProjectRestTest extends ZanataRestTest private final String RESOURCE_PATH = "/projects/p/"; IMocksControl mockControl = EasyMock.createControl(); Identity mockIdentity = mockControl.createMock(Identity.class); + SeamAutowire seam = SeamAutowire.instance(); @BeforeClass void beforeClass() @@ -58,12 +60,12 @@ protected void prepareDBUnitOperations() @Override protected void prepareResources() { - ProjectDAO projectDAO = new ProjectDAO(getSession()); - AccountDAO accountDAO = new AccountDAO(getSession()); - DocumentDAO documentDAO = new DocumentDAO(getSession()); - ETagUtils eTagUtils = new ETagUtils(getSession(), documentDAO); + seam.reset(); + seam.ignoreNonResolvable() + .use("session", getSession()) + .use("identity", mockIdentity); - ProjectService projectService = new ProjectService(projectDAO, accountDAO, mockIdentity, eTagUtils); + ProjectService projectService = seam.autowire(ProjectService.class); resources.add(projectService); }