package ch.elexis.core.services; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import ch.elexis.core.model.Identifiable; @Component public class StoreToStringService implements IStoreToStringService { private List<IStoreToStringContribution> contributions = new ArrayList<>(); @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) public synchronized void setCodeElementServiceContribution( IStoreToStringContribution contribution){ contributions.add(contribution); } public synchronized void unsetCodeElementServiceContribution( IStoreToStringContribution contribution){ contributions.remove(contribution); } private Map<Class<?>, IStoreToStringContribution> classToContributionMap = new HashMap<>(); private Cache<String, Identifiable> loadFromStringCache = CacheBuilder.newBuilder().expireAfterAccess(15, TimeUnit.SECONDS).maximumSize(100).build(); @Override public Optional<String> storeToString(Identifiable identifiable){ IStoreToStringContribution contribution = classToContributionMap.get(identifiable.getClass()); if (contribution != null) { return contribution.storeToString(identifiable); } for (IStoreToStringContribution iStoreToStringContribution : contributions) { Optional<String> string = iStoreToStringContribution.storeToString(identifiable); if (string.isPresent()) { classToContributionMap.put(identifiable.getClass(), iStoreToStringContribution); return string; } } return Optional.empty(); } @Override public Optional<Identifiable> loadFromString(String storeToString){ if (storeToString != null) { Identifiable cached = loadFromStringCache.getIfPresent(storeToString); if (cached != null) { return Optional.of(cached); } for (IStoreToStringContribution iStoreToStringContribution : contributions) { Optional<Identifiable> identifiable = iStoreToStringContribution.loadFromString(storeToString); if (identifiable.isPresent()) { loadFromStringCache.put(storeToString, identifiable.get()); return identifiable; } } } return Optional.empty(); } @Override public List<Identifiable> loadFromStringWithIdPart(String partialStoreToString){ List<Identifiable> ret = new ArrayList<>(); if (partialStoreToString != null) { for (IStoreToStringContribution iStoreToStringContribution : contributions) { List<Identifiable> loaded = iStoreToStringContribution.loadFromStringWithIdPart(partialStoreToString); if (!loaded.isEmpty()) { ret.addAll(loaded); } } } return ret.parallelStream().filter(Objects::nonNull).collect(Collectors.toList()); } @Override public Class<?> getEntityForType(String type){ if (type != null) { for (IStoreToStringContribution iStoreToStringContribution : contributions) { Class<?> loaded = iStoreToStringContribution.getEntityForType(type); if (loaded != null) { return loaded; } } } return null; } @Override public String getTypeForEntity(Object entityInstance){ if (entityInstance != null) { for (IStoreToStringContribution iStoreToStringContribution : contributions) { String loaded = iStoreToStringContribution.getTypeForEntity(entityInstance); if (loaded != null) { return loaded; } } } return null; } @Override public String getTypeForModel(Class<?> interfaze){ if (interfaze != null) { for (IStoreToStringContribution iStoreToStringContribution : contributions) { String loaded = iStoreToStringContribution.getTypeForModel(interfaze); if (loaded != null) { return loaded; } } } return null; } }