Skip to content

Package: AbstractKapuaConfigurableService

AbstractKapuaConfigurableService

nameinstructionbranchcomplexitylinemethod
AbstractKapuaConfigurableService(String, Domain, EntityManagerFactory)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
AbstractKapuaConfigurableService(String, Domain, EntityManagerFactory, AbstractEntityCacheFactory)
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
checkRequiredProperties(KapuaTocd, Map)
M: 29 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
createConfig(ServiceConfig)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getConfigMetadata(KapuaId)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getConfigMetadata(KapuaId, boolean)
M: 82 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 18 C: 0
0%
M: 1 C: 0
0%
getConfigValues(KapuaId)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getConfigValues(KapuaId, boolean)
M: 91 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 19 C: 0
0%
M: 1 C: 0
0%
getServicePid()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
isPropertyEnabled(KapuaTad, KapuaId)
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$createConfig$3(ServiceConfig, EntityManager)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$createConfig$4(ServiceConfig)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
lambda$getConfigValues$10(KapuaId, ServiceConfigListResult)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getConfigValues$8(ServiceConfigQueryImpl, EntityManager)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getConfigValues$9(KapuaId)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$processMetadata$7(boolean, KapuaId, KapuaTad)
M: 11 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$setConfigValues$11(UserService, String)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$setConfigValues$12(ServiceConfigQueryImpl, EntityManager)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$updateConfig$5(ServiceConfig, EntityManager)
M: 47 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
lambda$updateConfig$6(ServiceConfig)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
lambda$validateConfigurations$0(KapuaId, KapuaTad)
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$validateConfigurations$1(Map, Map, KapuaTad)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$validateConfigurations$2(KapuaTad)
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
processMetadata(KapuaTmetadata, KapuaId, boolean)
M: 46 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
readMetadata(String)
M: 21 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
setConfigValues(KapuaId, KapuaId, Map)
M: 185 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 36 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 22 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
toProperties(Map)
M: 30 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
toValues(KapuaTocd, Properties)
M: 42 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
updateConfig(ServiceConfig)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
validateConfigurations(KapuaTocd, Map, KapuaId, KapuaId)
M: 102 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 23 C: 0
0%
M: 1 C: 0
0%
validateNewConfigValuesCoherence(KapuaTocd, Map, KapuaId, KapuaId)
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2016, 2022 Eurotech and/or its affiliates and others
3: *
4: * This program and the accompanying materials are made
5: * available under the terms of the Eclipse Public License 2.0
6: * which is available at https://www.eclipse.org/legal/epl-2.0/
7: *
8: * SPDX-License-Identifier: EPL-2.0
9: *
10: * Contributors:
11: * Eurotech - initial API and implementation
12: * Red Hat Inc
13: *******************************************************************************/
14: package org.eclipse.kapua.commons.configuration;
15:
16: import org.apache.commons.lang3.tuple.Triple;
17: import org.eclipse.kapua.KapuaEntityNotFoundException;
18: import org.eclipse.kapua.KapuaException;
19: import org.eclipse.kapua.KapuaIllegalArgumentException;
20: import org.eclipse.kapua.KapuaIllegalNullArgumentException;
21: import org.eclipse.kapua.commons.cache.LocalCache;
22: import org.eclipse.kapua.commons.jpa.AbstractEntityCacheFactory;
23: import org.eclipse.kapua.commons.jpa.CacheFactory;
24: import org.eclipse.kapua.commons.jpa.EntityManagerContainer;
25: import org.eclipse.kapua.commons.jpa.EntityManagerFactory;
26: import org.eclipse.kapua.commons.security.KapuaSecurityUtils;
27: import org.eclipse.kapua.commons.service.internal.AbstractKapuaService;
28: import org.eclipse.kapua.commons.service.internal.KapuaServiceDisabledException;
29: import org.eclipse.kapua.commons.service.internal.ServiceDAO;
30: import org.eclipse.kapua.commons.service.internal.cache.EntityCache;
31: import org.eclipse.kapua.commons.setting.system.SystemSetting;
32: import org.eclipse.kapua.commons.setting.system.SystemSettingKey;
33: import org.eclipse.kapua.commons.util.ArgumentValidator;
34: import org.eclipse.kapua.commons.util.ResourceUtils;
35: import org.eclipse.kapua.commons.util.StringUtil;
36: import org.eclipse.kapua.commons.util.xml.XmlUtil;
37: import org.eclipse.kapua.locator.KapuaLocator;
38: import org.eclipse.kapua.model.KapuaEntityAttributes;
39: import org.eclipse.kapua.model.config.metatype.KapuaTad;
40: import org.eclipse.kapua.model.config.metatype.KapuaTmetadata;
41: import org.eclipse.kapua.model.config.metatype.KapuaTocd;
42: import org.eclipse.kapua.model.domain.Actions;
43: import org.eclipse.kapua.model.domain.Domain;
44: import org.eclipse.kapua.model.id.KapuaId;
45: import org.eclipse.kapua.service.account.Account;
46: import org.eclipse.kapua.service.authorization.AuthorizationService;
47: import org.eclipse.kapua.service.authorization.permission.PermissionFactory;
48: import org.eclipse.kapua.service.config.KapuaConfigurableService;
49: import org.eclipse.kapua.service.user.User;
50: import org.eclipse.kapua.service.user.UserService;
51: import org.xml.sax.SAXException;
52:
53: import javax.validation.constraints.NotNull;
54: import javax.xml.bind.JAXBException;
55: import javax.xml.namespace.QName;
56: import java.io.IOException;
57: import java.net.URL;
58: import java.nio.charset.StandardCharsets;
59: import java.util.HashMap;
60: import java.util.List;
61: import java.util.Map;
62: import java.util.Map.Entry;
63: import java.util.Objects;
64: import java.util.Properties;
65: import java.util.stream.Collectors;
66:
67: /**
68: * Base {@code abstract} {@link KapuaConfigurableService} implementation.
69: *
70: * @since 1.0.0
71: */
72: public abstract class AbstractKapuaConfigurableService extends AbstractKapuaService implements KapuaConfigurableService {
73:
74: private static final EntityCache PRIVATE_ENTITY_CACHE = AbstractKapuaConfigurableServiceCache.getInstance().createCache();
75: private static final int LOCAL_CACHE_SIZE_MAX = SystemSetting.getInstance().getInt(SystemSettingKey.TMETADATA_LOCAL_CACHE_SIZE_MAXIMUM, 100);
76:
77: private final Domain domain;
78: private final String pid;
79:
80: /**
81: * This cache is to hold the {@link KapuaTocd}s that are read from the metatype files.
82: * <p>
83: * The key is a {@link Triple} composed by:
84: * <ul>
85: * <li>The {@link KapuaConfigurableService} PID</li>
86: * <li>The ID of the {@link Account} for the current request</li>
87: * <li>A {@link Boolean} flag indicating whether disabled properties are excluded from the AD or not</li>
88: * </ul>
89: *
90: * @since 1.2.0
91: */
92: private static final LocalCache<Triple<String, KapuaId, Boolean>, KapuaTocd> KAPUA_TOCD_LOCAL_CACHE = new LocalCache<>(LOCAL_CACHE_SIZE_MAX, null);
93:
94: /**
95: * This cache only holds the {@link Boolean} value {@literal True} if the {@link KapuaTocd} has been already read from the file
96: * at least once, regardless of the value. With this we can know when a read from {@code KAPUA_TOCD_LOCAL_CACHE}
97: * returns {@literal null} because of the requested key is not present, and when the key is present but its actual value
98: * is {@literal null}.
99: *
100: * @since 1.2.0
101: */
102: private static final LocalCache<Triple<String, KapuaId, Boolean>, Boolean> KAPUA_TOCD_EMPTY_LOCAL_CACHE = new LocalCache<>(LOCAL_CACHE_SIZE_MAX, false);
103:
104: /**
105: * Constructor.
106: *
107: * @param pid The {@link KapuaConfigurableService} id.
108: * @param domain The {@link Domain} on which check access.
109: * @param entityManagerFactory The {@link EntityManagerFactory} that handles persistence unit
110: * @since 1.0.0
111: */
112: protected AbstractKapuaConfigurableService(String pid, Domain domain, EntityManagerFactory entityManagerFactory) {
113: this(pid, domain, entityManagerFactory, null);
114: }
115:
116: /**
117: * Constructor.
118: *
119: * @param pid The {@link KapuaConfigurableService} id.
120: * @param domain The {@link Domain} on which check access.
121: * @param entityManagerFactory The {@link EntityManagerFactory} that handles persistence unit
122: * @param abstractCacheFactory The {@link CacheFactory} that handles caching of the entities
123: * @since 1.2.0
124: */
125: protected AbstractKapuaConfigurableService(String pid, Domain domain, EntityManagerFactory entityManagerFactory, AbstractEntityCacheFactory abstractCacheFactory) {
126: super(entityManagerFactory, abstractCacheFactory);
127:
128: this.pid = pid;
129: this.domain = domain;
130: }
131:
132: /**
133: * Reads the {@link KapuaTmetadata} for the given {@link KapuaConfigurableService} pid.
134: *
135: * @param pid The {@link KapuaConfigurableService} pid
136: * @return The {@link KapuaTmetadata} for the given {@link KapuaConfigurableService} pid.
137: * @throws Exception
138: * @since 1.0.0
139: */
140: private static KapuaTmetadata readMetadata(String pid) throws JAXBException, SAXException, IOException {
141: URL url = ResourceUtils.getResource(String.format("META-INF/metatypes/%s.xml", pid));
142:
143:• if (url == null) {
144: return null;
145: }
146:
147: return XmlUtil.unmarshal(ResourceUtils.openAsReader(url, StandardCharsets.UTF_8), KapuaTmetadata.class);
148: }
149:
150: /**
151: * Validates the given {@link Map} of properties against the given {@link KapuaTocd}.
152: *
153: * @param ocd The reference {@link KapuaTocd}.
154: * @param updatedProps The properties to validate.
155: * @param scopeId The scope {@link KapuaId} which is going to be updated.
156: * @param parentId The parent scope {@link KapuaId}.
157: * @throws KapuaException
158: * @since 1.0.0
159: */
160: private void validateConfigurations(KapuaTocd ocd, Map<String, Object> updatedProps, KapuaId scopeId, KapuaId parentId)
161: throws KapuaException {
162:• if (ocd != null) {
163:
164: // Get Disabled Properties
165:• List<KapuaTad> disabledProperties = ocd.getAD().stream().filter(ad -> !isPropertyEnabled(ad, scopeId)).collect(Collectors.toList());
166:
167:• if (!disabledProperties.isEmpty()) {
168: // If there's any disabled property, read current values to overwrite the proposed ones
169: Map<String, Object> originalValues = getConfigValues(scopeId, false);
170:• if (originalValues != null) {
171: disabledProperties.forEach(disabledProp -> updatedProps.put(disabledProp.getId(), originalValues.get(disabledProp.getId())));
172: }
173: }
174:
175: // build a map of all the attribute definitions
176: Map<String, KapuaTad> attrDefs = ocd.getAD().stream().collect(Collectors.toMap(KapuaTad::getId, ad -> ad));
177:
178: // loop over the proposed property values
179: // and validate them against the definition
180:• for (Entry<String, Object> property : updatedProps.entrySet()) {
181:
182: String key = property.getKey();
183: KapuaTad attrDef = attrDefs.get(key);
184:
185: // is attribute undefined?
186:• if (attrDef == null) {
187: // we do not have an attribute descriptor to the validation
188: // against
189: // As OSGI insert attributes at runtime like service.pid,
190: // component.name,
191: // for the attribute for which we do not have a definition,
192: // just accept them.
193: continue;
194: }
195:
196: // validate the attribute value
197: Object objectValue = property.getValue();
198: String stringValue = StringUtil.valueToString(objectValue);
199:• if (stringValue != null) {
200: ValueTokenizer tokenizer = new ValueTokenizer(stringValue);
201: String result = tokenizer.validate(attrDef);
202:• if (result != null && !result.isEmpty()) {
203: throw new KapuaIllegalArgumentException(attrDef.getId(), result);
204: }
205: }
206: }
207:
208: checkRequiredProperties(ocd, updatedProps);
209:
210: validateNewConfigValuesCoherence(ocd, updatedProps, scopeId, parentId);
211: }
212: }
213:
214: /**
215: * Check the given {@link Map} of properties against the given {@link KapuaTocd} validating {@link KapuaTad#isRequired()}.
216: *
217: * @param ocd The reference {@link KapuaTocd}.
218: * @param updatedProps The properties to validate.
219: * @throws KapuaIllegalNullArgumentException if one of the required {@link KapuaTad} in {@link KapuaTocd} is missing in the given properties.
220: * @since 1.0.0
221: */
222: private void checkRequiredProperties(KapuaTocd ocd, Map<String, Object> updatedProps) throws KapuaIllegalNullArgumentException {
223: // Make sure all required properties are set
224:• for (KapuaTad attrDef : ocd.getAD()) {
225: // To the required attributes make sure a value is defined.
226:• if (Boolean.TRUE.equals(attrDef.isRequired()) && updatedProps.get(attrDef.getId()) == null) {
227: // If the default one is not defined, throw exception.
228: throw new KapuaIllegalNullArgumentException(attrDef.getId());
229: }
230: }
231: }
232:
233: /**
234: * Validates that the configurations is coherent.
235: * <p>
236: * By default returns true, but an extending {@link KapuaConfigurableService}s may have its own logic
237: *
238: * @param ocd The reference {@link KapuaTocd}.
239: * @param updatedProps The properties to validate.
240: * @param scopeId The scope {@link KapuaId} which is going to be updated.
241: * @param parentId The parent scope {@link KapuaId}.
242: * @return {@literal true} if the configuration is valid, {@literal false} otherwise
243: * @throws KapuaException
244: * @since 1.0.0
245: */
246: protected boolean validateNewConfigValuesCoherence(KapuaTocd ocd, Map<String, Object> updatedProps, KapuaId scopeId, KapuaId parentId) throws KapuaException {
247: return true;
248: }
249:
250: /**
251: * Converts the given {@link Map} properties map to {@link Properties}.
252: *
253: * @param values The {@link Map} properties to convert.
254: * @return The converted {@link Properties}
255: * @since 1.0.0
256: */
257: private static Properties toProperties(Map<String, Object> values) {
258: Properties props = new Properties();
259:• for (Entry<String, Object> entry : values.entrySet()) {
260:• if (entry.getValue() != null) {
261: props.setProperty(entry.getKey(), StringUtil.valueToString(entry.getValue()));
262: }
263: }
264:
265: return props;
266: }
267:
268: /**
269: * Converts the given {@link Properties} to a properties {@link Map}.
270: *
271: * @param ocd The reference {@link KapuaTocd}.
272: * @param props The {@link Properties} to convert
273: * @return The converted {@link Map} properties.
274: * @throws KapuaException
275: * @since 1.0.0
276: */
277: protected static Map<String, Object> toValues(@NotNull KapuaTocd ocd, Properties props) throws KapuaException {
278: Map<String, Object> values = new HashMap<>();
279:• for (KapuaTad ad : ocd.getAD()) {
280:• String valueStr = props == null ? ad.getDefault() : props.getProperty(ad.getId(), ad.getDefault());
281: Object value = StringUtil.stringToValue(ad.getType().value(), valueStr);
282: values.put(ad.getId(), value);
283: }
284:
285: return values;
286: }
287:
288: /**
289: * Persist the given {@link ServiceConfig}.
290: *
291: * @param serviceConfig The {@link ServiceConfig} to persist.
292: * @return The persisted {@link ServiceConfig}.
293: * @throws KapuaException
294: * @since 1.0.0
295: */
296: private ServiceConfig createConfig(ServiceConfig serviceConfig) throws KapuaException {
297:
298: return entityManagerSession.doTransactedAction(
299: EntityManagerContainer.<ServiceConfig>create()
300: .onResultHandler(em -> ServiceDAO.create(em, serviceConfig))
301: .onBeforeHandler(() -> {
302: PRIVATE_ENTITY_CACHE.removeList(serviceConfig.getScopeId(), pid);
303: return null;
304: })
305: );
306: }
307:
308: /**
309: * Updates the given {@link ServiceConfig}.
310: *
311: * @param serviceConfig The {@link ServiceConfig} to update.
312: * @return The updates {@link ServiceConfig}.
313: * @throws KapuaException
314: */
315: private ServiceConfig updateConfig(ServiceConfig serviceConfig)
316: throws KapuaException {
317: return entityManagerSession.doTransactedAction(EntityManagerContainer.<ServiceConfig>create()
318: .onResultHandler(em -> {
319:
320: ServiceConfig oldServiceConfig = ServiceConfigDAO.find(em, serviceConfig.getScopeId(), serviceConfig.getId());
321:• if (oldServiceConfig == null) {
322: throw new KapuaEntityNotFoundException(ServiceConfig.TYPE, serviceConfig.getId());
323: }
324:
325:• if (!Objects.equals(oldServiceConfig.getScopeId(), serviceConfig.getScopeId())) {
326: throw new KapuaIllegalArgumentException("serviceConfiguration.scopeId", serviceConfig.getScopeId().toStringId());
327: }
328:
329:• if (!oldServiceConfig.getPid().equals(serviceConfig.getPid())) {
330: throw new KapuaIllegalArgumentException("serviceConfiguration.pid", serviceConfig.getPid());
331: }
332:
333: // Update
334: return ServiceConfigDAO.update(em, serviceConfig);
335: })
336: .onBeforeHandler(() -> {
337: PRIVATE_ENTITY_CACHE.removeList(serviceConfig.getScopeId(), pid);
338: return null;
339: })
340: );
341: }
342:
343: @Override
344: public KapuaTocd getConfigMetadata(KapuaId scopeId) throws KapuaException {
345: return getConfigMetadata(scopeId, true);
346: }
347:
348: /**
349: * Gets the {@link KapuaTocd} for the given scope {@link KapuaId} and the current {@link KapuaConfigurableService}
350: * excluding disabled {@link KapuaTad} if requested.
351: *
352: * @param scopeId The scope {@link KapuaId}.
353: * @param excludeDisabled Whether to exclude disabled {@link KapuaTocd}s and {@link KapuaTad}s.
354: * @return The {@link KapuaTocd} available for the current {@link KapuaConfigurableService}.
355: * @throws KapuaException
356: * @since 1.3.0
357: */
358: protected KapuaTocd getConfigMetadata(KapuaId scopeId, boolean excludeDisabled) throws KapuaException {
359: //
360: // Argument validation
361: ArgumentValidator.notNull(scopeId, "scopeId");
362:
363: //
364: // Check disabled service
365:• if (!isServiceEnabled(scopeId)) {
366: throw new KapuaServiceDisabledException(pid);
367: }
368:
369: //
370: // Check access
371: KapuaLocator locator = KapuaLocator.getInstance();
372: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
373: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
374:
375: authorizationService.checkPermission(permissionFactory.newPermission(domain, Actions.read, scopeId));
376:
377: //
378: // Get the Tocd
379: // Keep distinct values for service PID, Scope ID and disabled properties included/excluded from AD
380: Triple<String, KapuaId, Boolean> cacheKey = Triple.of(pid, scopeId, excludeDisabled);
381: try {
382: // Check if the OCD is already in cache, but not in the "empty" cache
383: KapuaTocd tocd = KAPUA_TOCD_LOCAL_CACHE.get(cacheKey);
384:• if (tocd == null && !KAPUA_TOCD_EMPTY_LOCAL_CACHE.get(cacheKey)) {
385: // If not, read metadata and process it
386: tocd = processMetadata(readMetadata(pid), scopeId, excludeDisabled);
387: // If null, put it in the "empty" ocd cache, else put it in the "standard" cache
388:• if (tocd != null) {
389: // If the value is not null, put it in "standard" cache and remove the entry from the "empty" cache if present
390: KAPUA_TOCD_LOCAL_CACHE.put(cacheKey, tocd);
391: KAPUA_TOCD_EMPTY_LOCAL_CACHE.remove(cacheKey);
392: } else {
393: // If the value is null, just remember we already read it from file at least once
394: KAPUA_TOCD_EMPTY_LOCAL_CACHE.put(cacheKey, true);
395: }
396: }
397: return tocd;
398: } catch (Exception e) {
399: throw KapuaException.internalError(e);
400: }
401: }
402:
403: /**
404: * Process {@link KapuaTmetadata} to exclude disabled {@link KapuaTocd}s and {@link KapuaTad}s if requested.
405: *
406: * @param metadata The {@link KapuaTmetadata} to process.
407: * @param excludeDisabled Whether to exclude disabled {@link KapuaTocd}s and {@link KapuaTad}s.
408: * @return The processed {@link KapuaTocd}.
409: * @throws KapuaException
410: * @since 1.3.0
411: */
412: private KapuaTocd processMetadata(KapuaTmetadata metadata, KapuaId scopeId, boolean excludeDisabled) throws KapuaException {
413:• if (metadata != null && metadata.getOCD() != null && !metadata.getOCD().isEmpty()) {
414:• for (KapuaTocd ocd : metadata.getOCD()) {
415:• if (ocd.getId() != null && ocd.getId().equals(pid) && isServiceEnabled(scopeId)) {
416:• ocd.getAD().removeIf(ad -> excludeDisabled && !isPropertyEnabled(ad, scopeId));
417: return ocd;
418: }
419: }
420: }
421: return null;
422: }
423:
424: @Override
425: public Map<String, Object> getConfigValues(KapuaId scopeId) throws KapuaException {
426: return getConfigValues(scopeId, true);
427: }
428:
429: /**
430: * Gets {@link Map} properties for the given scope {@link KapuaId} and the current {@link KapuaConfigurableService}
431: * excluding disabled {@link KapuaTad} if requested.
432: *
433: * @param scopeId The scope {@link KapuaId}.
434: * @param excludeDisabled Whether to exclude disabled {@link KapuaTocd}s and {@link KapuaTad}s.
435: * @return The {@link Map} properties of the current {@link KapuaConfigurableService}.
436: * @throws KapuaException
437: * @since 1.3.0
438: */
439: protected Map<String, Object> getConfigValues(KapuaId scopeId, boolean excludeDisabled) throws KapuaException {
440: //
441: // Argument validation
442: ArgumentValidator.notNull(scopeId, "scopeId");
443:
444: //
445: // Check access
446: KapuaLocator locator = KapuaLocator.getInstance();
447: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
448: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
449: authorizationService.checkPermission(permissionFactory.newPermission(domain, Actions.read, scopeId));
450:
451: //
452: // Get configuration values
453: ServiceConfigQueryImpl query = new ServiceConfigQueryImpl(scopeId);
454:
455: query.setPredicate(
456: query.andPredicate(
457: query.attributePredicate(ServiceConfigAttributes.SERVICE_ID, pid),
458: query.attributePredicate(KapuaEntityAttributes.SCOPE_ID, scopeId)
459: )
460: );
461:
462: ServiceConfigListResult result = entityManagerSession.doAction(EntityManagerContainer.<ServiceConfigListResult>create()
463: .onResultHandler(em -> ServiceDAO.query(em, ServiceConfig.class, ServiceConfigImpl.class, new ServiceConfigListResultImpl(), query))
464: .onBeforeHandler(() -> (ServiceConfigListResult) PRIVATE_ENTITY_CACHE.getList(scopeId, pid))
465: .onAfterHandler(entity -> PRIVATE_ENTITY_CACHE.putList(scopeId, pid, entity)));
466:
467: Properties properties = null;
468:• if (result != null && !result.isEmpty()) {
469: properties = result.getFirstItem().getConfigurations();
470: }
471:
472: KapuaTocd ocd = getConfigMetadata(scopeId, excludeDisabled);
473:
474:• return ocd == null ? null : toValues(ocd, properties);
475: }
476:
477: @Override
478: public void setConfigValues(KapuaId scopeId, KapuaId parentId, Map<String, Object> values) throws KapuaException {
479: KapuaLocator locator = KapuaLocator.getInstance();
480: AuthorizationService authorizationService = locator.getService(AuthorizationService.class);
481: PermissionFactory permissionFactory = locator.getFactory(PermissionFactory.class);
482: KapuaTocd ocd = getConfigMetadata(scopeId, false);
483:
484: UserService userService = locator.getService(UserService.class);
485: String rootUserName = SystemSetting.getInstance().getString(SystemSettingKey.SYS_ADMIN_USERNAME);
486: User rootUser = KapuaSecurityUtils.doPrivileged(() -> userService.findByName(rootUserName));
487:
488: Map<String, Object> originalValues = getConfigValues(scopeId);
489:
490:• for (KapuaTad ad : ocd.getAD()) {
491: boolean allowSelfEdit = Boolean.parseBoolean(ad.getOtherAttributes().getOrDefault(new QName("allowSelfEdit"), "false"));
492:
493: boolean preventChange =
494: // if current user is not root user...
495:• !KapuaSecurityUtils.getSession().getUserId().equals(rootUser.getId()) &&
496: // current configuration does not allow self edit...
497: !allowSelfEdit &&
498: // a configuration for the current logged account is about to be changed...
499:• KapuaSecurityUtils.getSession().getScopeId().equals(scopeId) &&
500: // and the new value is different from the other one...
501:• !originalValues.get(ad.getId()).equals(values.get(ad.getId()));
502:
503:• if (preventChange) {
504: // ... prevent the change!
505: throw KapuaException.internalError(String.format("The configuration \"%s\" cannot be changed by this user in this account", ad.getId()));
506: }
507: }
508:
509: authorizationService.checkPermission(permissionFactory.newPermission(domain, Actions.write, scopeId));
510:
511: validateConfigurations(ocd, values, scopeId, parentId);
512:
513: ServiceConfigQueryImpl query = new ServiceConfigQueryImpl(scopeId);
514: query.setPredicate(
515: query.andPredicate(
516: query.attributePredicate(ServiceConfigAttributes.SERVICE_ID, pid),
517: query.attributePredicate(KapuaEntityAttributes.SCOPE_ID, scopeId)
518: )
519: );
520:
521: ServiceConfigListResult result = entityManagerSession.doAction(EntityManagerContainer.<ServiceConfigListResult>create().
522: onResultHandler(em -> ServiceDAO.query(em, ServiceConfig.class, ServiceConfigImpl.class, new ServiceConfigListResultImpl(), query))
523: );
524:
525: Properties props = toProperties(values);
526:• if (result == null || result.isEmpty()) {
527: // In not exists create then return
528: ServiceConfig serviceConfigNew = new ServiceConfigImpl(scopeId);
529: serviceConfigNew.setPid(pid);
530: serviceConfigNew.setConfigurations(props);
531:
532: createConfig(serviceConfigNew);
533: } else {
534: // If exists update it
535: ServiceConfig serviceConfig = result.getFirstItem();
536: serviceConfig.setConfigurations(props);
537:
538: updateConfig(serviceConfig);
539: }
540: }
541:
542: /**
543: * Checks if the given {@link KapuaTad} is enabled for the given scope {@link KapuaId}.
544: * <p>
545: * By default it returns {@code true}. {@link KapuaConfigurableService}s can change this behaviour if needed.
546: *
547: * @param ad The {@link KapuaTad} to check.
548: * @param scopeId The scope {@link KapuaId} for which to check.
549: * @return {@code true} if enabled, {@code false} otherwise.
550: * @since 1.3.0
551: */
552: protected boolean isPropertyEnabled(KapuaTad ad, KapuaId scopeId) {
553: return true;
554: }
555:
556: /**
557: * Gets the {@link KapuaConfigurableService} pid.
558: *
559: * @return The {@link KapuaConfigurableService} pid.
560: * @since 2.0.0
561: */
562: public String getServicePid() {
563: return pid;
564: }
565: }