All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cds.mtx.impl.MetaDataAccessorSingleModelImpl Maven / Gradle / Ivy

/*
 * ----------------------------------------------------------------
 * © 2019-2021 SAP SE or an SAP affiliate company. All rights reserved.
 * ----------------------------------------------------------------
 *
 */
package com.sap.cds.mtx.impl;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sap.cds.CdsException;
import com.sap.cds.mtx.MetaDataAccessor;
import com.sap.cds.mtx.ModelId;
import com.sap.cds.mtx.impl.MetaDataAccessorImpl.EdmxModelCreator;
import com.sap.cds.reflect.CdsModel;
import com.sap.cds.reflect.impl.CdsModelReader;

/**
 * Class that provides access to CDS and Edmx models read from java resource
 * folders
 */
public class MetaDataAccessorSingleModelImpl implements MetaDataAccessor {
	private static final Logger logger = LoggerFactory.getLogger(MetaDataAccessorSingleModelImpl.class);
	private final CdsModel cdsModel;
	private final String edmxFolder;
	private final ConcurrentHashMap keyToEdmx = new ConcurrentHashMap();
	// edmx as string,service name, model
	private final EdmxModelCreator edmxstrAndServiceToEdmxModel;

	/**
	 * @param cdsModelPath                 Path to the csn-file,including file name
	 * @param edmxFolder                   Path of edmx folder, null and empty are
	 *                                     allowed
	 * @param edmxstrAndServiceToEdmxModel Function that converts edmx model read as
	 *                                     string into generic type M
	 * @throws IOException
	 */
	public MetaDataAccessorSingleModelImpl(String cdsModelPath, String edmxFolder,
			EdmxModelCreator edmxstrAndServiceToEdmxModel) throws IOException {
		if (cdsModelPath != null && !cdsModelPath.isEmpty()) {
			try (InputStream is = MetaDataAccessorSingleModelImpl.class.getClassLoader()
					.getResourceAsStream(cdsModelPath)) {
				if (is == null) {
					throw new IOException("Cds model " + cdsModelPath + " not found");
				}
				cdsModel = CdsModelReader.read(is);
			}
		} else {
			logger.warn("No model path provided");
			cdsModel = null;
		}
		this.edmxFolder = edmxFolder;
		this.edmxstrAndServiceToEdmxModel = edmxstrAndServiceToEdmxModel;
	}

	@Override
	public M getEdmx(ModelId id, int maxAgeSeconds) throws CdsException {
		String serviceName = id.getServiceName().orElseThrow(() -> new CdsException("No service name specified"));
		String language = id.getLanguage().orElse("");
		ServiceAndLanguage key = new ServiceAndLanguage(language, serviceName);
		try {
			return keyToEdmx.computeIfAbsent(key, this::readEmdxFromResource);
		} catch (RuntimeException e) {
			throw new CdsException(e);
		}
	}

	private M readEmdxFromResource(ServiceAndLanguage key) throws RuntimeException {
		if (edmxstrAndServiceToEdmxModel == null) {
			throw new RuntimeException("No function to convert string into edmx model provided");
		}
		String edmxAsString;
		try (InputStream is = MetaDataAccessorSingleModelImpl.class.getClassLoader()
				.getResourceAsStream(getResourceName(key.service, key.language))) {
			if (is == null) {
				throw new IOException("Edmx file " + getResourceName(key.service, key.language) + " not found");
			}
			edmxAsString = IOUtils.toString(is, StandardCharsets.UTF_8);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return edmxstrAndServiceToEdmxModel.parse(edmxAsString, key.service);
	}

	private String getResourceName(String serviceName, String language) {
		String completePathStr;
		if (edmxFolder == null || edmxFolder.isEmpty()) {
			completePathStr = serviceName;
		} else {
			completePathStr = edmxFolder + "/" + serviceName;
		}
		if (language != null && !language.isEmpty()) {
			completePathStr += "_" + language.toLowerCase(Locale.ENGLISH);
		}
		completePathStr += ".xml";
		return completePathStr;
	}

	@Override
	public I18n getI18n(ModelId modelId, int maxAgeSeconds) {
		return new I18n(null, Collections.emptyMap());
	}

	@Override
	public CdsModel getCdsModel(ModelId modelId, int maxAgeSeconds) throws CdsException {
		return cdsModel;
	}

	@Override
	public void refresh(String tenantId, int maxAgeSeconds) {
		// intentionally left empty, no cache
	}

	@Override
	public void evict(String tenantId) {
		// intentionally left empty, no cache
	}

	private static class ServiceAndLanguage {
		private final String language;
		private final String service;

		public ServiceAndLanguage(String language, String service) {
			this.language = language;
			this.service = service;
		}

		@Override
		public boolean equals(Object o) {
			if (this == o)
				return true;
			if (o == null || getClass() != o.getClass())
				return false;
			ServiceAndLanguage that = (ServiceAndLanguage) o;
			return Objects.equals(language, that.language) && service.equals(that.service);
		}

		@Override
		public int hashCode() {
			return Objects.hash(language, service);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy