Commit 6133841b authored by Marco Descher's avatar Marco Descher 🏔

[16258] Introduce ITextReplacementService

parent 27093007
Pipeline #12093 passed with stages
in 4 minutes and 42 seconds
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0" activate="activate" name="ch.elexis.core.services.TextReplacementService">
<service>
<provide interface="ch.elexis.core.services.ITextReplacementService"/>
</service>
<reference cardinality="0..n" field="placeholderResolvers" interface="ch.elexis.core.text.ITextPlaceholderResolver" name="placeholderResolvers"/>
<implementation class="ch.elexis.core.services.TextReplacementService"/>
</scr:component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ch.elexis.core.services.internal.text.PatientTextPlaceholderResolver">
<service>
<provide interface="ch.elexis.core.text.ITextPlaceholderResolver"/>
</service>
<implementation class="ch.elexis.core.services.internal.text.PatientTextPlaceholderResolver"/>
</scr:component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="ch.elexis.core.services.internal.text.TerminTextPlaceholderResolver">
<service>
<provide interface="ch.elexis.core.text.ITextPlaceholderResolver"/>
</service>
<implementation class="ch.elexis.core.services.internal.text.TerminTextPlaceholderResolver"/>
</scr:component>
\ No newline at end of file
package ch.elexis.core.services;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import ch.elexis.core.text.ITextPlaceholderResolver;
@Component
public class TextReplacementService implements ITextReplacementService {
@Reference(cardinality = ReferenceCardinality.MULTIPLE)
private List<ITextPlaceholderResolver> placeholderResolvers;
private static final String DONT_SHOW_REPLACEMENT_ERRORS = "*";
public static final String MATCH_TEMPLATE = "\\[[" + DONT_SHOW_REPLACEMENT_ERRORS //$NON-NLS-1$
+ "]?[-a-zA-ZäöüÄÖÜéàè_ ]+\\.[-a-zA-Z0-9äöüÄÖÜéàè_ ]+\\]";
private Pattern matchTemplate;
@Activate
public void activate(){
matchTemplate = Pattern.compile(MATCH_TEMPLATE);
}
@Override
public String performReplacement(IContext context, String template){
Matcher matcher = matchTemplate.matcher(template);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String found = matcher.group();
matcher.appendReplacement(sb,
Matcher.quoteReplacement((String) replacePlaceholder(context, found)));
}
matcher.appendTail(sb);
return sb.toString();
}
private String replacePlaceholder(IContext context, String placeholder){
String substring = placeholder.substring(1, placeholder.length() - 1);
String[] split = substring.split("\\.");
if (split.length > 1) {
for (ITextPlaceholderResolver resolver : placeholderResolvers) {
if (resolver.getSupportedType().equalsIgnoreCase(split[0])) {
Optional<String> result = resolver.replaceByTypeAndAttribute(context,
substring.substring(split[0].length() + 1));
if (result.isPresent()) {
return result.get();
}
}
}
}
return "?";
}
}
package ch.elexis.core.services.internal.text;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.osgi.service.component.annotations.Component;
import ch.elexis.core.interfaces.ILocalizedEnum;
import ch.elexis.core.model.IPatient;
import ch.elexis.core.services.IContext;
import ch.elexis.core.text.ITextPlaceholderResolver;
import ch.elexis.core.text.PlaceholderAttribute;
@Component
public class PatientTextPlaceholderResolver implements ITextPlaceholderResolver {
@Override
public String getSupportedType(){
return "Patient";
}
@Override
public List<PlaceholderAttribute> getSupportedAttributes(){
return Arrays.asList(PatientAttribute.values()).stream()
.map(m -> new PlaceholderAttribute(getSupportedType(), m.name(), m.getLocaleText()))
.collect(Collectors.toList());
}
@Override
public Optional<String> replaceByTypeAndAttribute(IContext context, String attribute){
IPatient patient = context.getTyped(IPatient.class).orElse(null);
if (patient != null) {
return Optional.ofNullable(replace(patient, attribute.toLowerCase()));
}
return Optional.empty();
}
private String replace(IPatient patient, String lcAttribute){
PatientAttribute patientAttribut = searchEnum(PatientAttribute.class, lcAttribute);
switch (patientAttribut) {
case Name:
return patient.getLastName();
case Vorname:
return patient.getFirstName();
default:
break;
}
return null;
}
private enum PatientAttribute implements ILocalizedEnum {
Name("Tag des Termins im Format dd.MM.yyyy"), Vorname("Zugehöriger Bereich");
final String description;
private PatientAttribute(String description){
this.description = description;
}
@Override
public String getLocaleText(){
return description;
}
}
}
package ch.elexis.core.services.internal.text;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.osgi.service.component.annotations.Component;
import ch.elexis.core.interfaces.ILocalizedEnum;
import ch.elexis.core.model.IAppointment;
import ch.elexis.core.services.IContext;
import ch.elexis.core.text.ITextPlaceholderResolver;
import ch.elexis.core.text.PlaceholderAttribute;
import ch.rgw.tools.TimeTool;
@Component
public class TerminTextPlaceholderResolver implements ITextPlaceholderResolver {
@Override
public String getSupportedType(){
return "Termin";
}
@Override
public List<PlaceholderAttribute> getSupportedAttributes(){
return Arrays.asList(TerminAttribute.values()).stream()
.map(m -> new PlaceholderAttribute(getSupportedType(), m.name(), m.getLocaleText()))
.collect(Collectors.toList());
}
@Override
public Optional<String> replaceByTypeAndAttribute(IContext context, String attribute){
IAppointment appointment = context.getTyped(IAppointment.class).orElse(null);
if (appointment != null) {
return Optional.ofNullable(replace(appointment, attribute.toLowerCase()));
}
return Optional.empty();
}
private String replace(IAppointment appointment, String lcAttribute){
LocalDateTime value;
TerminAttribute attribute = searchEnum(TerminAttribute.class, lcAttribute);
switch (attribute) {
case Tag:
value = appointment.getStartTime();
return new TimeTool(value).toString(TimeTool.DATE_GER);
case Bereich:
return appointment.getSchedule();
case Zeit:
value = appointment.getStartTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
return formatter.format(value);
default:
return null;
}
}
private enum TerminAttribute implements ILocalizedEnum {
Tag("Tag des Termins im Format dd.MM.yyyy"), Bereich("Zugehöriger Bereich"),
Zeit("Startzeitpunkt im Format hh:mm");
final String description;
private TerminAttribute(String description){
this.description = description;
}
@Override
public String getLocaleText(){
return description;
}
}
}
package ch.elexis.core.services;
/**
* Perform replacement of text templates according to
* <a href="https://medelexis.ch/wp-content/uploads/Tabelle_Platzhalter.pdf">Elexis Platzhalter</a>.
* Cannot use IDataAccess as this is available in ch.elexis.core.data only.
*/
public interface ITextReplacementService {
/**
* @param context
* to apply during replacement
* @param template
* the source text
* @return replaced result
*/
public String performReplacement(IContext context, String template);
}
package ch.elexis.core.text;
import java.util.List;
import java.util.Optional;
import ch.elexis.core.services.IContext;
/**
* Resolve an attribute on a given supported type.
*/
public interface ITextPlaceholderResolver {
/**
* @return the type this resolver acts upon. E.g. Patient
*/
String getSupportedType();
/**
*
* @return the attributes resolvable
*/
List<PlaceholderAttribute> getSupportedAttributes();
/**
* replace the given attribute considering the provided context
*
* @param context
* @param attribute
* @return
*/
Optional<String> replaceByTypeAndAttribute(IContext context, String attribute);
/**
* Case-Insensitive load of an enumeration value
*
* @param <T>
* @param enumeration
* @param search
* @return
*/
default <T extends Enum<?>> T searchEnum(Class<T> enumeration, String search){
for (T each : enumeration.getEnumConstants()) {
if (each.name().compareToIgnoreCase(search) == 0) {
return each;
}
}
return null;
}
}
package ch.elexis.core.text;
/**
* A typed-attribute that may be resolved to a string
*/
public class PlaceholderAttribute {
private final String typeName;
private final String attributeName;
private final String description;
public PlaceholderAttribute(String typeName, String attributeName, String description){
this.typeName = typeName;
this.attributeName = attributeName;
this.description = description;
}
public String getTypeName(){
return typeName;
}
public String getAttributeName(){
return attributeName;
}
public String getDescription(){
return description;
}
}
......@@ -20,7 +20,7 @@ import ch.elexis.core.utils.OsgiServiceUtil;
IElexisEnvironmentServiceTest.class, ILabServiceTest.class, IStoreToStringServiceTest.class,
IStickerServiceTest.class, IAppointmentServiceTest.class, IUserServiceTest.class,
IMessageServiceTest.class, IVirtualFilesystemServiceTest.class, IXidServiceTest.class,
IMedicationServiceTest.class
IMedicationServiceTest.class, ITextReplacementServiceTest.class
})
public class AllServiceTests {
......
package ch.elexis.core.services;
import static org.junit.Assert.assertEquals;
import java.time.LocalDateTime;
import org.junit.BeforeClass;
import org.junit.Test;
import ch.elexis.core.model.IAppointment;
import ch.elexis.core.model.builder.IAppointmentBuilder;
import ch.elexis.core.utils.OsgiServiceUtil;
public class ITextReplacementServiceTest extends AbstractServiceTest {
private ITextReplacementService textReplacementService =
OsgiServiceUtil.getService(ITextReplacementService.class).get();
private IContextService contextService =
OsgiServiceUtil.getService(IContextService.class).get();
private static IAppointment appointment;
@BeforeClass
public static void beforeClass(){
LocalDateTime ldt = LocalDateTime.of(2019, 12, 12, 12, 12);
appointment = new IAppointmentBuilder(coreModelService, "testSchedule", ldt,
ldt.plusHours(1), "type", "state").buildAndSave();
}
@Test
public void patientReplacement(){
contextService.setActivePatient(AllServiceTests.getPatient());
String template = "Hallo [Patient.Name] [Patient.Vorname]";
String replaced =
textReplacementService.performReplacement(contextService.getRootContext(), template);
assertEquals("Hallo Patient Test", replaced);
}
@Test
public void terminReplacement(){
contextService.getRootContext().setTyped(appointment);
String template = "[Termin.Tag] [Termin.zeit] [Termin.Bereich]";
String replaced =
textReplacementService.performReplacement(contextService.getRootContext(), template);
assertEquals("12.12.2019 12:12 testSchedule", replaced);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment