diff --git a/stub-server/src/main/java/org/zanata/rest/service/MockGlossaryResource.java b/stub-server/src/main/java/org/zanata/rest/service/MockGlossaryResource.java index 9d9822ab..bc18fc52 100644 --- a/stub-server/src/main/java/org/zanata/rest/service/MockGlossaryResource.java +++ b/stub-server/src/main/java/org/zanata/rest/service/MockGlossaryResource.java @@ -32,6 +32,9 @@ import org.zanata.common.LocaleId; import org.zanata.rest.GlossaryFileUploadForm; import org.zanata.rest.dto.GlossaryEntry; +import org.zanata.rest.dto.GlossaryResults; + +import com.google.common.collect.Lists; /** * @author Patrick Huang @@ -43,31 +46,39 @@ public class MockGlossaryResource implements GlossaryResource { UriInfo uriInfo; @Override - public Response getInfo() { - return null; + public Response getInfo(String qualifiedName) { + return Response.ok(GlossaryResource.GLOBAL_QUALIFIED_NAME).build(); } @Override public Response getEntries(LocaleId srcLocale, LocaleId transLocale, int page, int sizePerPage, String filter, - String sort) { + String sort, String qualifiedName) { return MockResourceUtil.notUsedByClient(); } @Override public Response downloadFile(@DefaultValue("csv") String fileType, - String locales) { + String locales, String qualifiedName) { return MockResourceUtil.notUsedByClient(); } @Override - public Response post(List glossaryEntries) { - GenericEntity> genericEntity = - new GenericEntity>(glossaryEntries) { - }; + public Response post(List glossaryEntries, String locale, + String qualifiedName) { + GlossaryResults results = new GlossaryResults(); + results.setGlossaryEntries(glossaryEntries); + GenericEntity genericEntity = + new GenericEntity(results) { + }; return Response.ok(genericEntity).build(); } + @Override + public Response getQualifiedName() { + return null; + } + @Override public Response upload(GlossaryFileUploadForm glossaryFileUploadForm) { return MockResourceUtil.notUsedByClient(); @@ -79,7 +90,7 @@ public Response deleteEntry(Long id) { } @Override - public Response deleteAllEntries() { + public Response deleteAllEntries(String qualifiedName) { return null; } } diff --git a/stub-server/src/main/java/org/zanata/rest/service/MockProjectResource.java b/stub-server/src/main/java/org/zanata/rest/service/MockProjectResource.java index 4ee00f04..8c8e4709 100644 --- a/stub-server/src/main/java/org/zanata/rest/service/MockProjectResource.java +++ b/stub-server/src/main/java/org/zanata/rest/service/MockProjectResource.java @@ -22,6 +22,7 @@ package org.zanata.rest.service; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -38,6 +39,9 @@ public class MockProjectResource implements ProjectResource { @Context UriInfo uriInfo; + @PathParam("projectSlug") + String projectSlug; + @Override public Response head() { return MockResourceUtil.notUsedByClient(); @@ -53,5 +57,11 @@ public Response get() { public Response put(Project project) { return Response.created(uriInfo.getRequestUri()).build(); } + + @Override + public Response getGlossaryQualifiedName() { + String qualifiedName = "project/" + projectSlug; + return Response.ok(qualifiedName).build(); + } } diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptions.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptions.java index 8ed003cf..e4fc3003 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptions.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptions.java @@ -15,4 +15,10 @@ public interface ConfigurableGlossaryOptions extends ConfigurableOptions { usage = "Configuration file, eg zanata.xml", required = false) public void setConfig(File config); + + public String getProject(); + + @Option(name = "--project", metaVar = "PROJ", + usage = "Project slug (id) within Zanata server. Required for project glossary") + public void setProject(String project); } diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptionsImpl.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptionsImpl.java index f6046548..4d57de39 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptionsImpl.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/ConfigurableGlossaryOptionsImpl.java @@ -15,11 +15,18 @@ public abstract class ConfigurableGlossaryOptionsImpl extends ConfigurableOption */ private File config = new File("zanata.xml"); + private String project; + @Override public File getConfig() { return config; } + @Override + public String getProject() { + return project; + } + @Option(name = "--config", metaVar = "FILENAME", usage = "Configuration file, eg zanata.xml", required = false) @@ -27,4 +34,9 @@ public void setConfig(File config) { this.config = config; } + @Option(name = "--project", metaVar = "PROJ", + usage = "Required for project glossary") + public void setProject(String project) { + this.project = project; + } } diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/delete/GlossaryDeleteCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/delete/GlossaryDeleteCommand.java index 4541f93b..e6b9468a 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/delete/GlossaryDeleteCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/delete/GlossaryDeleteCommand.java @@ -42,12 +42,12 @@ public class GlossaryDeleteCommand extends ConfigurableCommand { private static final Logger log = LoggerFactory .getLogger(GlossaryDeleteCommand.class); - private final GlossaryClient glossaryClient; + private final GlossaryClient client; public GlossaryDeleteCommand(GlossaryDeleteOptions opts, RestClientFactory clientFactory) { super(opts, clientFactory); - glossaryClient = getClientFactory().getGlossaryClient(); + client = getClientFactory().getGlossaryClient(); } public GlossaryDeleteCommand(GlossaryDeleteOptions opts) { @@ -61,18 +61,30 @@ public void run() throws Exception { if (!StringUtils.isEmpty(getOpts().getId())) { log.info("Entry id to delete: {}", getOpts().getId()); } + if (StringUtils.isNotBlank(getOpts().getProject())) { + log.info("Project: {}", getOpts().getProject()); + } log.info("Delete entire glossary?: {}", getOpts().getAllGlossary()); + + if (!getOpts().getAllGlossary() && StringUtils.isBlank(getOpts().getId())) { + throw new RuntimeException("Option '--id' is required."); + } + + String project = getOpts().getProject(); + String qualifiedName = + StringUtils.isBlank(project) ? client.getGlobalQualifiedName() + : client.getProjectQualifiedName(project); + if (getOpts().getAllGlossary()) { if (getOpts().isInteractiveMode()) { ConsoleInteractor console = new ConsoleInteractorImpl(getOpts()); console.printf(Question, "\nAre you sure (y/n)? "); console.expectYes(); } - glossaryClient.deleteAll(); - } else if (!StringUtils.isEmpty(getOpts().getId())) { - glossaryClient.delete(getOpts().getId()); - } else { - throw new RuntimeException("Option 'zanata.resId' is required."); + Integer deletedCount = client.deleteAll(qualifiedName); + log.info("Deleted glossary entry: " + deletedCount.intValue()); + } else { + client.delete(getOpts().getId(), qualifiedName); } } } diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java index b5338bab..4483734a 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java @@ -68,20 +68,28 @@ public void run() throws Exception { if (!fileType.equalsIgnoreCase("po") && !fileType.equalsIgnoreCase("csv")) { throw new RuntimeException( - "Option 'zanata.fileType' is not valid. Please use 'csv' or 'po'"); + "Option '--file-type' is not valid. Please use 'csv' or 'po'"); } log.info("Server: {}", getOpts().getUrl()); log.info("Username: {}", getOpts().getUsername()); log.info("File type: {}", fileType); + if (StringUtils.isNotBlank(getOpts().getProject())) { + log.info("Project: {}", getOpts().getProject()); + } ImmutableList transLang = getOpts().getTransLang(); if (transLang != null && !transLang.isEmpty()) { log.info("Translation language: {}", Joiner.on(",").join(transLang)); } - log.info("pulling glossary from server"); + String project = getOpts().getProject(); + String qualifiedName = + StringUtils.isBlank(project) ? client.getGlobalQualifiedName() + : client.getProjectQualifiedName(project); + + log.info("Pulling glossary from server"); ClientResponse response = - client.downloadFile(fileType, transLang); + client.downloadFile(fileType, transLang, qualifiedName); if (response .getClientResponseStatus() == ClientResponse.Status.NOT_FOUND) { diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/push/GlossaryPushCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/push/GlossaryPushCommand.java index d4fdc6eb..965bf4e3 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/push/GlossaryPushCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/push/GlossaryPushCommand.java @@ -43,6 +43,8 @@ import org.zanata.rest.client.RestClientFactory; import org.zanata.rest.dto.GlossaryEntry; +import com.google.common.collect.Lists; + import static org.zanata.client.commands.glossary.push.GlossaryPushOptions.DEFAULT_SOURCE_LANG; /** @@ -73,10 +75,8 @@ public GlossaryPushCommand(GlossaryPushOptions opts) { LocaleId transLocaleId = StringUtils.isNotBlank(transLang) ? new LocaleId(transLang) : null; glossaryReaders.put("po", new GlossaryPoReader( - srcLocaleId, transLocaleId, getOpts().getBatchSize())); - glossaryReaders - .put("csv", new GlossaryCSVReader(srcLocaleId, - getOpts().getBatchSize())); + srcLocaleId, transLocaleId)); + glossaryReaders.put("csv", new GlossaryCSVReader(srcLocaleId)); } private AbstractGlossaryPushReader getReader(String fileExtension) { @@ -106,6 +106,9 @@ public void run() throws Exception { log.info("Username: {}", getOpts().getUsername()); log.info("Source language: {}", DEFAULT_SOURCE_LANG); log.info("Translation language: {}", getOpts().getTransLang()); + if (StringUtils.isNotBlank(getOpts().getProject())) { + log.info("Project: {}", getOpts().getProject()); + } log.info("Glossary file: {}", getOpts().getFile()); log.info("Batch size: {}", getOpts().getBatchSize()); @@ -126,9 +129,14 @@ public void run() throws Exception { String fileExtension = validateFileExtensionWithTransLang(); + String project = getOpts().getProject(); + String qualifiedName = + StringUtils.isBlank(project) ? client.getGlobalQualifiedName() + : client.getProjectQualifiedName(project); + AbstractGlossaryPushReader reader = getReader(fileExtension); - log.info("pushing glossary document [{}] to server", + log.info("Pushing glossary document [{}] to server", glossaryFile.getName()); Reader inputStreamReader = @@ -136,19 +144,27 @@ public void run() throws Exception { "UTF-8"); BufferedReader br = new BufferedReader(inputStreamReader); - List> glossaries = reader.extractGlossary(br); + Map> glossaries = + reader.extractGlossary(br, qualifiedName); int totalEntries = 0; - for (List entries : glossaries) { - totalEntries = totalEntries + entries.size(); - log.debug("total entries:" + totalEntries); + for (Map.Entry> entries : glossaries + .entrySet()) { + totalEntries = totalEntries + entries.getValue().size(); + log.info("Total entries:" + totalEntries); } int totalDone = 0; - for (List entries : glossaries) { - client.post(entries); - totalDone = totalDone + entries.size(); - log.info("Pushed " + totalDone + " of " + totalEntries + " entries"); + for (Map.Entry> entry : glossaries + .entrySet()) { + List> batches = + Lists.partition(entry.getValue(), getOpts().getBatchSize()); + for (List batch : batches) { + client.post(batch, entry.getKey(), qualifiedName); + totalDone = totalDone + batch.size(); + log.info("Pushed " + totalDone + " of " + totalEntries + + " entries"); + } } } } diff --git a/zanata-maven-plugin/src/main/java/org/zanata/maven/GlossaryMojo.java b/zanata-maven-plugin/src/main/java/org/zanata/maven/GlossaryMojo.java index 8712cc7d..a5909eed 100644 --- a/zanata-maven-plugin/src/main/java/org/zanata/maven/GlossaryMojo.java +++ b/zanata-maven-plugin/src/main/java/org/zanata/maven/GlossaryMojo.java @@ -20,6 +20,13 @@ public abstract class GlossaryMojo */ private File config; + /** + * Project slug (id) within Zanata server. Required for project glossary. + * + * @parameter expression="${zanata.project}" + */ + private String project; + @Override public File getConfig() { return config; @@ -29,4 +36,14 @@ public File getConfig() { public void setConfig(File config) { this.config = config; } + + @Override + public String getProject() { + return project; + } + + @Override + public void setProject(String project) { + this.project = project; + } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java index 0b31574d..48d83d6e 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java @@ -28,9 +28,12 @@ import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.MediaType; +import org.zanata.common.LocaleId; import org.zanata.rest.dto.GlossaryEntry; import org.zanata.rest.dto.Project; +import org.zanata.rest.dto.QualifiedName; import org.zanata.rest.service.GlossaryResource; +import org.zanata.rest.service.ProjectResource; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; @@ -51,7 +54,8 @@ public class GlossaryClient { baseUri = factory.getBaseUri(); } - public void post(List glossaryEntries) { + public void post(List glossaryEntries, LocaleId localeId, + String qualifiedName) { Type genericType = new GenericType>() { }.getType(); @@ -59,32 +63,53 @@ public void post(List glossaryEntries) { new GenericEntity>(glossaryEntries, genericType); - webResource().path("entries").type(MediaType.APPLICATION_XML_TYPE) - .post(entity); + webResource().path("entries").queryParam("locale", localeId.getId()) + .queryParam("qualifiedName", qualifiedName) + .type(MediaType.APPLICATION_XML_TYPE).post(entity); } public ClientResponse downloadFile(String fileType, - ImmutableList transLang) { + ImmutableList transLang, String qualifiedName) { if (transLang != null && !transLang.isEmpty()) { return webResource().path("file").queryParam("fileType", fileType) .queryParam("locales", Joiner.on(",").join(transLang)) + .queryParam("qualifiedName", qualifiedName) .get(ClientResponse.class); } return webResource().path("file").queryParam("fileType", fileType) + .queryParam("qualifiedName", qualifiedName) .get(ClientResponse.class); } - public void delete(String id) { + public void delete(String id, String qualifiedName) { webResource().path("entries/" + id) - .delete(); + .queryParam("qualifiedName", qualifiedName).delete(); } - public void deleteAll() { - webResource().delete(); + public int deleteAll(String qualifiedName) { + return webResource().queryParam("qualifiedName", qualifiedName) + .delete(Integer.class); + } + + public String getProjectQualifiedName(String projectSlug) { + return projectGlossaryWebResource(projectSlug).path("qualifiedName") + .get(QualifiedName.class).getName(); + } + + public String getGlobalQualifiedName() { + return webResource().path("qualifiedName").get(QualifiedName.class) + .getName(); } private WebResource webResource() { return factory.getClient().resource(baseUri) .path(GlossaryResource.SERVICE_PATH); } + + private WebResource projectGlossaryWebResource(String projectSlug) { + return factory.getClient() + .resource(factory.getBaseUri()) + .path("projects").path("p").path(projectSlug).path("glossary"); + } + } diff --git a/zanata-rest-client/src/test/java/org/zanata/rest/client/GlossaryClientTest.java b/zanata-rest-client/src/test/java/org/zanata/rest/client/GlossaryClientTest.java index 2aecc60c..2f92c703 100644 --- a/zanata-rest-client/src/test/java/org/zanata/rest/client/GlossaryClientTest.java +++ b/zanata-rest-client/src/test/java/org/zanata/rest/client/GlossaryClientTest.java @@ -27,9 +27,11 @@ import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; +import org.zanata.common.LocaleId; import org.zanata.rest.dto.Glossary; import org.zanata.rest.dto.GlossaryEntry; import org.zanata.rest.dto.ResultList; +import org.zanata.rest.service.GlossaryResource; import org.zanata.rest.service.StubbingServerRule; public class GlossaryClientTest { @@ -47,7 +49,8 @@ public void setUp() throws Exception { @Test public void testPut() throws Exception { List glossaryEntries = new ArrayList<>(); - client.post(glossaryEntries); + client.post(glossaryEntries, LocaleId.DE, + GlossaryResource.GLOBAL_QUALIFIED_NAME); MockServerTestUtil.verifyServerRespondSuccessStatus(); } }