diff --git a/g11n-ws/build.gradle b/g11n-ws/build.gradle index b73c7f9ad..8ce876af2 100644 --- a/g11n-ws/build.gradle +++ b/g11n-ws/build.gradle @@ -74,6 +74,7 @@ subprojects{ postgresqlVersion = "42.1.4" druidVersion = "1.1.8" awsS3Version = "1.12.741" + gcpGcsVersion = "2.42.0" swaggerVersion = "3.0.0" icu4jVersion = "60.3" diff --git a/g11n-ws/modules/md-data-api-gcsimpl/build.gradle b/g11n-ws/modules/md-data-api-gcsimpl/build.gradle new file mode 100644 index 000000000..2e6f8b646 --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/build.gradle @@ -0,0 +1,39 @@ +//Copyright 2019-2024 VMware, Inc. +//SPDX-License-Identifier: EPL-2.0 +apply plugin: 'java-library' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +archivesBaseName = 'md-data-api-gcsimpl' + + + +jar { + manifest { + attributes 'Implementation-Title': 'md-data-api-gcsimpl', + 'Implementation-Version': version + } +} + +dependencies { + + api project(":md-data-api") + api project(":vip-common") + compileOnly("org.springframework.boot:spring-boot") + compileOnly("org.springframework.boot:spring-boot-starter-data-jpa") + compileOnly("org.slf4j:slf4j-api:$slf4jVersion") + compileOnly("org.apache.commons:commons-lang3:$commonsLangVersion") + compileOnly("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion") + implementation ("com.google.cloud:google-cloud-storage:2.42.0") + implementation ("com.google.cloud:google-cloud-storage-control:2.42.0") + +} + +bootJar { + enabled = false +} + +jar { + classifier = '' + enabled = true +} diff --git a/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsComponentChannelDao.java b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsComponentChannelDao.java new file mode 100644 index 000000000..95d51729c --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsComponentChannelDao.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019-2024 VMware, Inc. + * SPDX-License-Identifier: EPL-2.0 + */ +package com.vmware.vip.messages.data.dao.gcs.impl; + +import java.io.ByteArrayInputStream; +import java.nio.channels.Channels; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.BlobId; +import com.vmware.vip.common.constants.ConstantsChar; +import com.vmware.vip.common.i18n.resourcefile.ResourceFilePathGetter; +import com.vmware.vip.messages.data.dao.api.IComponentChannelDao; +import com.vmware.vip.messages.data.dao.exception.DataException; +import com.vmware.vip.messages.data.dao.model.ResultMessageChannel; +import com.vmware.vip.messages.data.gcs.conf.GcsClient; +import com.vmware.vip.messages.data.gcs.conf.GcsConfig; +import com.vmware.vip.messages.data.gcs.util.GcsUtils; + +@Profile("gcs") +@Repository +public class GcsComponentChannelDao implements IComponentChannelDao { + private static Logger logger = LoggerFactory.getLogger(GcsComponentChannelDao.class); + + @Autowired + private GcsClient gcsClient; + + @Autowired + private GcsConfig config; + + @Override + public List getTransReadableByteChannels(String productName, String version, + List components, List locales) throws DataException { + logger.debug("GcsComponentChannelDao.getTransReadableByteChannels()-> product={}, version={}, components={}, locales={}", + productName, version, components, locales); + List resultChannels = new ArrayList(); + for (String component : components) { + for (String locale : locales) { + String filePath = GcsUtils.genProductVersionGcsPath(productName, version) + component + ConstantsChar.BACKSLASH + + ResourceFilePathGetter.getLocalizedJSONFileName(locale); + BlobId blobId = BlobId.of(config.getBucketName(), filePath); + Blob blob = gcsClient.getGcsStorage().get(blobId); + if (blob != null) { + byte[] content = gcsClient.getGcsStorage().readAllBytes(config.getBucketName(), filePath); + if (content != null) { + ByteArrayInputStream is = new ByteArrayInputStream(content); + resultChannels.add(new ResultMessageChannel(component, locale, Channels.newChannel(is))); + } + + } + + } + } + logger.debug("fileSize: {}", resultChannels.size()); + + return resultChannels; + } + +} diff --git a/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsMultComponentDaoImpl.java b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsMultComponentDaoImpl.java new file mode 100644 index 000000000..a21da5658 --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsMultComponentDaoImpl.java @@ -0,0 +1,82 @@ +/** + * Copyright 2019-2024 VMware, Inc. + * SPDX-License-Identifier: EPL-2.0 + */ +package com.vmware.vip.messages.data.dao.gcs.impl; + +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; +import com.vmware.vip.common.constants.ConstantsChar; +import com.vmware.vip.messages.data.dao.api.IMultComponentDao; +import com.vmware.vip.messages.data.dao.api.IOneComponentDao; +import com.vmware.vip.messages.data.dao.exception.DataException; +import com.vmware.vip.messages.data.dao.model.ResultI18Message; + +/** + * this class get the bundle json from bundle file + */ +@Repository +@Profile("gcs") +public class GcsMultComponentDaoImpl implements IMultComponentDao { + private static Logger logger = LoggerFactory.getLogger(GcsMultComponentDaoImpl.class); + + @Autowired + private IOneComponentDao oneComponentDao; + + /** + * get the bundle files from gcs service + */ + @Override + public List get2JsonStrs(String productName, String version, List components, List locales) + throws DataException { + logger.debug("begin get2JsonStrs"); + List bundles = new ArrayList<>(); + if (components == null || locales == null) { + throw new DataException("Gcs No component or locale"); + } + for (String component : components) { + for (String locale : locales) { + try { + bundles.add(oneComponentDao.get2JsonStr(productName, version, component, locale)); + } catch (DataException e) { + logger.warn(e.getMessage(), e); + } + } + } + logger.debug("end get2JsonStrs"); + return bundles; + } + + /** + * get the bundle files and convert to ResultI18Message + */ + @Override + public List get(String productName, String version, List components, List locales) + throws DataException { + logger.debug("begin get"); + List bundles = new ArrayList<>(); + if (components == null || locales == null) { + throw new DataException("Gcs No component or locale"); + } + for (String component : components) { + for (String locale : locales) { + try { + bundles.add(oneComponentDao.get(productName, version, component, locale)); + } catch (DataException e) { + throw new DataException("Gcs Failed to get for " + productName + ConstantsChar.BACKSLASH + version + + ConstantsChar.BACKSLASH + component + ConstantsChar.BACKSLASH + locale + ".", e); + } + } + } + logger.debug("end get"); + if (bundles.size() == 0) { + throw new DataException("Gcs No bundle is found."); + } + return bundles; + } +} \ No newline at end of file diff --git a/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsOneComponentDaoImpl.java b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsOneComponentDaoImpl.java new file mode 100644 index 000000000..74c38f643 --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsOneComponentDaoImpl.java @@ -0,0 +1,143 @@ +/** + * Copyright 2019-2024 VMware, Inc. + * SPDX-License-Identifier: EPL-2.0 + */ +package com.vmware.vip.messages.data.dao.gcs.impl; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; +import org.springframework.util.StringUtils; +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.BlobId; +import com.google.cloud.storage.BlobInfo; +import com.google.cloud.storage.Storage; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.vmware.vip.common.constants.ConstantsChar; +import com.vmware.vip.common.constants.ConstantsFile; +import com.vmware.vip.common.constants.ConstantsKeys; +import com.vmware.vip.common.i18n.resourcefile.ResourceFilePathGetter; +import com.vmware.vip.messages.data.dao.api.IOneComponentDao; +import com.vmware.vip.messages.data.dao.exception.DataException; +import com.vmware.vip.messages.data.dao.model.ResultI18Message; +import com.vmware.vip.messages.data.gcs.conf.GcsClient; +import com.vmware.vip.messages.data.gcs.conf.GcsConfig; +import com.vmware.vip.messages.data.gcs.util.GcsUtils; + +/** + * This java class is used to handle translation bundle file or translation + */ +@Repository +@Profile("gcs") +public class GcsOneComponentDaoImpl implements IOneComponentDao { + + @Autowired + private GcsClient gcsClient; + + @Autowired + private GcsConfig config; + + static final String GCS_NOT_EXIST_STR = "GC Storage File doesn't exist: "; + private static Logger logger = LoggerFactory.getLogger(GcsOneComponentDaoImpl.class); + + /** + * get one component bundle files from s3 server and convert to ResultI18Message + * Object + */ + @Override + public ResultI18Message get(String productName, String version, String component, String locale) + throws DataException { + String jsonStr = get2JsonStr(productName, version, component, locale); + ObjectMapper mapper = new ObjectMapper(); + ResultI18Message result = null; + try { + result = mapper.readValue(jsonStr, ResultI18Message.class); + } catch (IOException e) { + String errorLog = ConstantsKeys.FATA_ERROR + e.getMessage(); + logger.error(errorLog, e); + throw new DataException(GCS_NOT_EXIST_STR); + } + if (result != null) { + result.setProduct(productName); + result.setVersion(version); + result.setComponent(component); + result.setLocale(locale); + } else { + throw new DataException(GCS_NOT_EXIST_STR); + } + return result; + } + + /** + * get one component bundle files from s3 server as json String + */ + @Override + public String get2JsonStr(String productName, String version, String component, String locale) + throws DataException { + logger.debug("GcsOneComponentDaoImpl.get2JsonStr()"); + String filePath = GcsUtils.genProductVersionGcsPath(productName, version) + component + ConstantsChar.BACKSLASH + + ResourceFilePathGetter.getLocalizedJSONFileName(locale); + BlobId blobId = BlobId.of(config.getBucketName(), filePath); + Blob blob = gcsClient.getGcsStorage().get(blobId); + if (blob != null) { + byte[] content = blob.getContent(); + if (content != null) { + return new String(content, StandardCharsets.UTF_8); + } + } + + throw new DataException(GCS_NOT_EXIST_STR + filePath); + } + + @Override + public boolean add(String productName, String version, String component, String locale, + Map messages) throws DataException { + return false; + } + + /** + * update the component bundle file to remote S3 server + */ + @Override + public boolean update(String productName, String version, String componentParam, String locale, + Map messages) throws DataException { + logger.debug("GcsOneComponentDaoImpl.update()-> productName={}, component={}, version={}, locale={}, messages={}", + productName, componentParam, version, locale, messages); + String component = componentParam; + if (StringUtils.isEmpty(component)) { + component = ConstantsFile.DEFAULT_COMPONENT; + } + String filePath = GcsUtils.genProductVersionGcsPath(productName, version) + component + ConstantsChar.BACKSLASH + + ResourceFilePathGetter.getLocalizedJSONFileName(locale); + Map json = new HashMap(); + json.put(ConstantsKeys.COMPONENT, component); + json.put(ConstantsKeys.lOCALE, locale); + json.put(ConstantsKeys.MESSAGES, messages); + String content; + try { + content = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(json); + } catch (JsonProcessingException e) { + throw new DataException(ConstantsKeys.FATA_ERROR + "Failed to convert content to file: " + filePath + ".", + e); + } + BlobId blobId = BlobId.of(config.getBucketName(), filePath); + BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build(); + Storage.BlobTargetOption precondition = Storage.BlobTargetOption + .generationMatch(gcsClient.getGcsStorage().get(config.getBucketName(), filePath).getGeneration()); + gcsClient.getGcsStorage().create(blobInfo, content.getBytes(StandardCharsets.UTF_8), precondition); + return true; + } + + @Override + public boolean delete(String productName, String version, String component, String locale) throws DataException { + return false; + } + +} diff --git a/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsProductDaoImpl.java b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsProductDaoImpl.java new file mode 100644 index 000000000..b1ad45b54 --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/dao/gcs/impl/GcsProductDaoImpl.java @@ -0,0 +1,176 @@ +/** + * Copyright 2019-2024 VMware, Inc. + * SPDX-License-Identifier: EPL-2.0 + */ +package com.vmware.vip.messages.data.dao.gcs.impl; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import com.google.api.gax.paging.Page; +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.BlobId; +import com.google.cloud.storage.Storage.BlobListOption; +import com.vmware.vip.common.constants.ConstantsChar; +import com.vmware.vip.common.constants.ConstantsFile; +import com.vmware.vip.messages.data.dao.api.IProductDao; +import com.vmware.vip.messages.data.dao.exception.DataException; +import com.vmware.vip.messages.data.gcs.conf.GcsClient; +import com.vmware.vip.messages.data.gcs.conf.GcsConfig; +import com.vmware.vip.messages.data.gcs.util.GcsUtils; + +/** + * this class use to get the properties of a version bundle files + */ +@Repository +@Profile("gcs") +public class GcsProductDaoImpl implements IProductDao { + + private static Logger logger = LoggerFactory.getLogger(GcsProductDaoImpl.class); + + @Autowired + private GcsClient gcsClient; + + @Autowired + private GcsConfig config; + + /** + * get the compose list from gcs service + */ + @Override + public List getComponentList(String productName, String version) throws DataException { + List componentList = new ArrayList(); + String filePathPrefix = GcsUtils.genProductVersionGcsPath(productName, version); + Page blobs = gcsClient.getGcsStorage().list(config.getBucketName(), BlobListOption.prefix(filePathPrefix), + BlobListOption.currentDirectory()); + if (blobs == null) { + throw new DataException("Can't find Gcs resource from " + productName + "\\" + version); + } + + for (Blob blob : blobs.iterateAll()) { + logger.debug("componentList->blob.getName()= {}", blob.getName()); + if (blob.isDirectory()) { + String dir = blob.getName().replace(filePathPrefix, ""); + // remove the trailing slash in dir + componentList.add(dir.substring(0, dir.length() - 1)); + } + } + + if (componentList.size() == 0) { + throw new DataException("Gcs Component list is empty."); + } + + return componentList; + } + + /** + * get locale list from gcs service + */ + @Override + public List getLocaleList(String productName, String version) throws DataException { + List localeList = new ArrayList(); + String filePathPrefix = GcsUtils.genProductVersionGcsPath(productName, version); + Page blobs = gcsClient.getGcsStorage().list(config.getBucketName(), + BlobListOption.prefix(filePathPrefix)); + if (blobs == null) { + throw new DataException("Can't find Gcs resource from " + productName + "\\" + version); + } + + for (Blob blob : blobs.iterateAll()) { + logger.debug("localeList->blob.getName()= {}", blob.getName()); + String gcsobKey = blob.getName().replace(filePathPrefix, ""); + if (!gcsobKey.equals("") && (!gcsobKey.startsWith(ConstantsFile.CREATION_INFO)) + && (!gcsobKey.startsWith(ConstantsFile.VERSION_FILE))) { + String resultKey = gcsobKey.split(ConstantsChar.BACKSLASH)[1]; + String localeKey = GcsUtils.getLocaleByFileName(resultKey); + if (localeKey != null && !localeList.contains(localeKey)) { + localeList.add(localeKey); + } + } + } + + if (localeList.size() == 0) { + throw new DataException("Gcs Locale list is empty."); + } + return localeList; + } + + /** + * get bundle version from gcs service + */ + @Override + public String getVersionInfo(String productName, String version) throws DataException { + String filePath = GcsUtils.genProductVersionGcsPath(productName, version) + ConstantsFile.VERSION_FILE; + String result = null; + try { + byte[] content = gcsClient.getGcsStorage().readAllBytes(config.getBucketName(), filePath); + if (content != null) { + result = new String(content, StandardCharsets.UTF_8); + } + } catch (Exception e) { + logger.warn(e.getMessage(), e); + throw new DataException("File is not existing: " + filePath); + } + if (result == null) { + throw new DataException("File is not existing: " + filePath); + } + return result; + } + + /** + * get one product's all available versions + */ + @Override + public List getVersionList(String productName) throws DataException { + String basePath = GcsUtils.GCS_L10N_BUNDLES_PATH + productName + ConstantsChar.BACKSLASH; + Page blobs = gcsClient.getGcsStorage().list(config.getBucketName(), BlobListOption.prefix(basePath), + BlobListOption.currentDirectory()); + + if (blobs == null) { + throw new DataException(productName + " no available version in gcs"); + } + + List versionList = new ArrayList<>(); + for (Blob blob : blobs.iterateAll()) { + logger.debug("versionList->blob.getName()= {}", blob.getName()); + if (blob.isDirectory()) { + String dir = blob.getName().replace(basePath, ""); + // remove the trailing slash in dir + versionList.add(dir.substring(0, dir.length() - 1)); + } + } + + if (versionList.size() == 0) { + throw new DataException(productName + " no available version in gcs"); + } + + return versionList; + } + + /** + * Get the content of the Allow List by gcs service + */ + @Override + public String getAllowProductListContent(String gcsPath) throws DataException { + BlobId blobId = BlobId.of(config.getAllowListBucketName(), gcsPath); + Blob blob = gcsClient.getGcsStorage().get(blobId); + if (blob != null) { + byte[] content = blob.getContent(); + if (content != null) { + return new String(content, StandardCharsets.UTF_8); + } else { + return null; + } + } else { + return null; + } + } + +} diff --git a/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/conf/GcsClient.java b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/conf/GcsClient.java new file mode 100644 index 000000000..04b1c42db --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/conf/GcsClient.java @@ -0,0 +1,57 @@ +/** + * Copyright 2019-2024 VMware, Inc. + * SPDX-License-Identifier: EPL-2.0 + */ +package com.vmware.vip.messages.data.gcs.conf; + +import jakarta.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import com.google.cloud.storage.Bucket; +import com.google.cloud.storage.BucketInfo; +import com.google.cloud.storage.Storage; +import com.google.cloud.storage.StorageOptions; + +/** + * the class use gcs configurations to initialize gcs client environment + */ +@Configuration +@Profile("gcs") +public class GcsClient { + + private final static Logger LOGGER = LoggerFactory.getLogger(GcsClient.class); + + private static Storage gcsStorage; + + @Autowired + private GcsConfig gcsConfig; + + @PostConstruct + protected void initGcsClient() { + + gcsStorage = StorageOptions.newBuilder() + .setProjectId(gcsConfig.getProjectId()) + .build() + .getService(); + if ( gcsStorage.get(gcsConfig.getBucketName()) == null ) { + Bucket bucket = gcsStorage.create(BucketInfo.of(gcsConfig.getBucketName())); + // Verify that the bucket was created by retrieving it and checking its location. + if (!bucket.exists()) { + LOGGER.error("create new bucket failure: {}", gcsConfig.getBucketName()); + } else { + LOGGER.info("create new bucket location: {}", bucket.asBucketInfo().getLocation()); + } + } else { + LOGGER.info("Bucket {} already exists", gcsConfig.getBucketName()); + } + + } + + public synchronized Storage getGcsStorage() { + return gcsStorage; + } + +} diff --git a/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/conf/GcsConfig.java b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/conf/GcsConfig.java new file mode 100644 index 000000000..29e3c4f79 --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/conf/GcsConfig.java @@ -0,0 +1,59 @@ +/** + * Copyright 2019-2024 VMware, Inc. + * SPDX-License-Identifier: EPL-2.0 + */ +package com.vmware.vip.messages.data.gcs.conf; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + + +/** + * the configuration of the gcs client + */ +@Configuration +@Profile("gcs") +public class GcsConfig { + + /** + * the gcs region name + */ + @Value("${gcs.region:us-east1}") + private String gcsRegion; + + /** + * the gcs project id + */ + @Value("${gcs.projectId}") + private String projectId; + + /** + * the gcs buncket Name + */ + @Value("${gcs.bucketName}") + private String bucketName; + + @Value("${allow.list.path.bucketName:}") + private String allowListBucketName; + + public String getProjectId() { + return projectId; + } + + public String getBucketName() { + return bucketName; + } + + public String getGcsRegion() { + return gcsRegion; + } + + public String getAllowListBucketName() { + if (this.allowListBucketName != null && (!this.allowListBucketName.isBlank())){ + return this.allowListBucketName; + }else { + return this.bucketName; + } + } +} diff --git a/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/util/GcsUtils.java b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/util/GcsUtils.java new file mode 100644 index 000000000..b289a0170 --- /dev/null +++ b/g11n-ws/modules/md-data-api-gcsimpl/src/main/java/com/vmware/vip/messages/data/gcs/util/GcsUtils.java @@ -0,0 +1,51 @@ +/** + * Copyright 2019-2024 VMware, Inc. + * SPDX-License-Identifier: EPL-2.0 + */ +package com.vmware.vip.messages.data.gcs.util; + +import com.vmware.vip.common.constants.ConstantsChar; +import com.vmware.vip.common.constants.ConstantsFile; +import com.vmware.vip.common.constants.ConstantsUnicode; + +public class GcsUtils { + public static final String GCS_L10N_BUNDLES_PATH = + "l10n" + ConstantsChar.BACKSLASH + "bundles" + ConstantsChar.BACKSLASH; + + private GcsUtils() { + } + + /** + * generate the product version path + */ + public static String genProductVersionGcsPath(String productName, String version) { + StringBuilder path = new StringBuilder(); + path.append(GCS_L10N_BUNDLES_PATH); + path.append(productName); + path.append(ConstantsChar.BACKSLASH); + path.append(version); + path.append(ConstantsChar.BACKSLASH); + return path.toString(); + + } + + /** + * get the locale by message file name + */ + public static String getLocaleByFileName(String fileName) { + String locale = null; + if (fileName.endsWith(ConstantsFile.FILE_TPYE_JSON) + && (!fileName.endsWith(ConstantsFile.CREATION_INFO)) + && (!fileName.endsWith(ConstantsFile.VERSION_FILE))) { + locale = fileName.substring(fileName.indexOf(ConstantsFile.LOCAL_FILE_SUFFIX) + 8, + fileName.lastIndexOf(ConstantsChar.DOT)); + if (!locale.equals(ConstantsChar.EMPTY)) { + locale = locale.replaceFirst(ConstantsChar.UNDERLINE, ConstantsChar.EMPTY); + } else { + locale = ConstantsUnicode.EN; + } + } + return locale; + } + +} diff --git a/g11n-ws/settings.gradle b/g11n-ws/settings.gradle index b1e4ba44a..55e9708fd 100644 --- a/g11n-ws/settings.gradle +++ b/g11n-ws/settings.gradle @@ -1,4 +1,4 @@ -//Copyright 2019-2022 VMware, Inc. +//Copyright 2019-2024 VMware, Inc. //SPDX-License-Identifier: EPL-2.0 rootProject.name = 'singleton' include ':vip-common' @@ -22,9 +22,11 @@ include ':md-restful-l10n-synch' include ':tool-trans-fetcher' include ':vip-resources' include ':md-data-api-s3impl' +include ':md-data-api-gcsimpl' include ':vip-manager-lite-i18n' project(':vip-manager-lite-i18n').projectDir = "$rootDir/vip-manager-lite-i18n" as File project(':md-data-api-s3impl').projectDir = "$rootDir/modules/md-data-api-s3impl" as File +project(':md-data-api-gcsimpl').projectDir = "$rootDir/modules/md-data-api-gcsimpl" as File project(':vip-common').projectDir = "$rootDir/vip-common" as File project(':vip-manager-i18n').projectDir = "$rootDir/vip-manager-i18n" as File project(':vip-manager-l10n').projectDir = "$rootDir/vip-manager-l10n" as File diff --git a/g11n-ws/vip-manager-i18n/build.gradle b/g11n-ws/vip-manager-i18n/build.gradle index 7baa5d6a7..41e121c9f 100644 --- a/g11n-ws/vip-manager-i18n/build.gradle +++ b/g11n-ws/vip-manager-i18n/build.gradle @@ -35,6 +35,7 @@ dependencies { api project(":md-data-api-pgimpl") }else{ api project(":md-data-api-s3impl") + api project(":md-data-api-gcsimpl") api project(":md-data-api-bundleimpl") } api project(":vip-common") @@ -139,7 +140,7 @@ processResources { excludes =[] if (project.hasProperty('datatype') && project.getProperty('datatype') == 'pgdb') { println "begin to exclude S3 and bundle builder configuration files" - excludes=['**/application-s3.properties', '**/application-bundle.properties', '/l10n'] + excludes=['**/application-s3.properties', '**/application-gcs.properties', '**/application-bundle.properties', '/l10n'] }else { println "begin to exclude pgdb builder configuration file" excludes=['**/application-pgdb.properties'] diff --git a/g11n-ws/vip-manager-i18n/src/main/resources/application-gcs.properties b/g11n-ws/vip-manager-i18n/src/main/resources/application-gcs.properties new file mode 100644 index 000000000..bcf7dfcef --- /dev/null +++ b/g11n-ws/vip-manager-i18n/src/main/resources/application-gcs.properties @@ -0,0 +1,124 @@ +## +#Copyright 2019-2022 VMware, Inc. +#SPDX-License-Identifier: EPL-2.0 +## + +# SPRING CONFIG (ConfigFileApplicationListener) +spring.config.name= # config file name (default to 'application') +spring.config.location= # location of config file + +# IDENTITY (ContextIdApplicationContextInitializer) +spring.application.name=Singleton + +# logging +logging.config=classpath:log4j2-spring.xml + + +#RSA secret file +secret.rsa.publicKeyPath=# +secret.rsa.privateKeyPath=# + +# EMBEDDED SERVER CONFIGURATION (ServerProperties) +server.port=8090 +server.max-http-header-size=8192 +server.scheme=https/http +server.https.key-store=classpath:vip.jks +server.https.key-store-password=123456 +server.https.key-password=123456 +server.https.key-store-type=JKS +server.https.key-alias=server +server.http.port=8091 +server.trace.enable=false +#graceful shutdown +server.shutdown=graceful +spring.lifecycle.timeout-per-shutdown-phase=30s + +#collection source server +source.cache.flag = false +source.cache.server.url = https://localhost:8088 +#Limit maximum request body bytes in an HTTP request when collect source +source.request.max-size = 10485760 + +gcs.projectId=#### +gcs.bucketName=#### + +#pseudo.enabled=false +#pseudo.locale=latest +pseudo.existSourceTag=#@ +pseudo.notExistSourceTag=@@ + +#CSP authentication on/off default false +csp.api.auth.enable=false +##vmware internal csp authentication url +csp.auth.url=#### +csp.auth.issuer=#### +csp.auth.refresh-interval-sec=30 + +#authority config +vipservice.authority.enable=false +#the time unit is minute +vipservice.authority.token.expiretime=525600 +#the jwt secret +vipservice.authority.jwt.secret=# +#ldap server url +vipservice.authority.ldap.server.url=#### +#ldap domain +vipservice.authority.ldap.tdomain=### +#ldap searchbase +vipservice.authority.ldap.searchbase=#### + +#cross-domain configuration +vipservice.cross.domain.enable=true +vipservice.cross.domain.allowCredentials=true +vipservice.cross.domain.alloworigin=* +vipservice.cross.domain.allowmethods=GET, POST, PUT, DELETE, OPTIONS +vipservice.cross.domain.allowheaders=csp-auth-token, Content-Type, x-xmp-ui, Authorization +vipservice.cross.domain.maxage=3600 + +#Cache-Control +cache-control.value=max-age=604800, public + +#swagger3-ui switch +#springfox.documentation.swagger-ui.enabled=true +#springfox.documentation.swagger-ui.base-url=/i18n/api/doc +#springfox.documentation.openApi.v3.path=/i18n/api/doc/v3/api-docs +#springfox.documentation.swagger-ui.server.url=https://vmtest.prd.com +#springfox.documentation.swagger-ui.server.description=test server +#spring.mvc.pathmatch.matching-strategy= + +#spring doc +springdoc.swagger-ui.enabled=true +springdoc.swagger-ui.disable-swagger-default-url=true +springdoc.swagger-ui.use-root-path=true +springdoc.swagger-ui.path=/i18n/api/doc/swagger-ui/index.html +#springdoc.swagger-ui.server.url=https://vmtest.prd.com +#springdoc.swagger-ui.server.description=test server +springdoc.api-docs.enabled=true +springdoc.api-docs.path=/i18n/api/doc/v3/api-docs + + +#microsoftstore mt config +mt.server=https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to= +#mt.key= +mt.translatedMax=500 +mt.translatedCount=20 + +#actuator +management.endpoints.jmx.exposure.exclude=* +management.endpoints.web.exposure.include=info, health +management.endpoints.web.base-path=/actuator + +#Configure the status of gzip, including on, off +config.gzip.enable = on +#Set Minimum size to trigger gzip. +config.gzip.minsize = 2048 +#request IDs print in log that defined by customer +config.client.requestIds=csp-request-id + +#Allow list configuration +allow.list.path=l10n/bundles/bundle.json +#allow list.path.bucketName=### + +#Singleton cache switch +singleton.cache.enable=true +