package hu.blackbelt.encryption.services.impl;

import hu.blackbelt.encryption.services.Encryptor;
import lombok.extern.slf4j.Slf4j;
import org.osgi.service.component.annotations.*;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component(immediate = true)
@Slf4j
public class ConfigDecryptor implements hu.blackbelt.encryption.services.ConfigDecryptor {

    private static final String FN_NAME = "ENC";
    private static final Pattern PATTERN_WITHOUT_ALIAS = Pattern.compile("^" + FN_NAME + "\\((.*)\\)$");
    private static final Pattern PATTERN_WITH_ALIAS = Pattern.compile("^" + FN_NAME + "\\((.*)\\s*,\\s*(.*)\\)$");

    private static final String DEFAULT_ENCRYPTOR_ALIAS = "default";

    private Map<String, Encryptor> encryptors = new HashMap<>();

    @Reference(policyOption = ReferencePolicyOption.GREEDY, unbind = "unregisterEncryptor", cardinality = ReferenceCardinality.AT_LEAST_ONE)
    void registerEncryptor(final Encryptor encryptor) {
        encryptors.put(encryptor.getAlias(), encryptor);
    }

    void unregisterEncryptor(final Encryptor encryptor) {
        encryptors.remove(encryptor.getAlias());
    }

    @Override
    public String decrypt(final String encryptedMessage) {
        final Matcher mWithAias = PATTERN_WITH_ALIAS.matcher(encryptedMessage);
        final String encrypted;
        final String alias;
        if (mWithAias.matches()) {
            encrypted = mWithAias.group(1);
            alias = mWithAias.group(2);
        } else {
            final Matcher mWithoutAias = PATTERN_WITHOUT_ALIAS.matcher(encryptedMessage);
            if (mWithoutAias.matches()) {
                encrypted = mWithoutAias.group(1);
                alias = DEFAULT_ENCRYPTOR_ALIAS;
            } else {
                throw new IllegalArgumentException("Invalid encrypted message format");
            }
        }

        final Encryptor enc = encryptors.get(alias);
        if (enc == null) {
            log.warn("Registered encryptor instances: " + encryptors.keySet());
            throw new IllegalStateException("Encryptor with alias '" + alias + "' not found");
        }
        final String decrypted = enc.decrypt(encrypted);

        return decrypted;
    }

    @Override
    public boolean isEncrypted(final String value) {
        return value != null ? PATTERN_WITHOUT_ALIAS.matcher(value).matches() : false;
    }
}

@@ -52,84 +52,168 @@
 ort 
-hu.blackbelt.encryption.services.Encryptor;%0Aimport lombok.extern.slf4j.Slf4j
+lombok.extern.slf4j.Slf4j;%0Aimport org.osgi.framework.BundleContext;%0Aimport org.osgi.framework.InvalidSyntaxException;%0Aimport org.osgi.framework.ServiceReference
 ;%0Aim
@@ -277,17 +277,26 @@
 va.util.
-*
+Collection
 ;%0Aimport
@@ -571,30 +571,16 @@
  PATTERN
-_WITHOUT_ALIAS
  = Patte
@@ -754,498 +754,171 @@
 ate 
-static final String DEFAULT_ENCRYPTOR_ALIAS = %22default%22;%0A%0A    private Map%3CString, Encryptor%3E encryptors = new HashMap%3C%3E();%0A%0A    @Reference(policyOption = ReferencePolicyOption.GREEDY, unbind = %22unregisterEncryptor%22, cardinality = ReferenceCardinality.AT_LEAST_ONE)%0A    void registerEncryptor(final Encryptor encryptor) %7B%0A        encryptors.put(encryptor.getAlias(), encryptor);%0A    %7D%0A%0A    void unregisterEncryptor(final Encryptor encryptor) %7B%0A        encryptors.remove(encryptor.getAlias())
+BundleContext context;%0A%0A    @Activate%0A    void start(final BundleContext context) %7B%0A        this.context = context;%0A    %7D%0A%0A    void stop() %7B%0A        context = null
 ;%0A  
@@ -1315,38 +1315,24 @@
 as = PATTERN
-_WITHOUT_ALIAS
 .matcher(enc
@@ -1468,31 +1468,12 @@
 s = 
-DEFAULT_ENCRYPTOR_ALIAS
+null
 ;%0A  
@@ -1616,80 +1616,107 @@
     
-final Encryptor enc = encryptors.get(alias);%0A        if (enc ==
+try %7B%0A            final String filter = alias != null ? %22(encryptor.alias=%22 + alias + %22)%22 :
  null
-) %7B%0A
+;%0A 
     
@@ -1726,77 +1726,218 @@
     
- log.warn(%22Registered encryptor instances: %22 + encryptors.keySet());%0A
+final Collection%3CServiceReference%3Chu.blackbelt.encryption.services.Encryptor%3E%3E srs = context.getServiceReferences(hu.blackbelt.encryption.services.Encryptor.class, filter);%0A            if (srs.isEmpty()) %7B%0A    
     
@@ -2027,34 +2027,42 @@
 ound%22);%0A        
-%7D%0A
+    %7D%0A    
         final St
@@ -2063,30 +2063,342 @@
 nal 
-String decrypted = enc
+hu.blackbelt.encryption.services.Encryptor encryptor = context.getService(srs.iterator().next());%0A%0A            if (srs.size() %3E 1) %7B%0A                log.warn(%22More than 1 encryptors found for alias: %22 + alias + %22, decryption is nondeterministic (used alias: %22 + encryptor.getAlias() + %22)%22);%0A            %7D%0A%0A            return encryptor
 .dec
@@ -2414,25 +2414,24 @@
 ypted);%0A
-%0A
         
 return d
@@ -2426,25 +2426,141 @@
     
-return decrypted;
+%7D catch (InvalidSyntaxException ex) %7B%0A            throw new IllegalStateException(%22Invalid encryptor alias: %22 + alias, ex);%0A        %7D
 %0A   
@@ -2672,22 +2672,8 @@
 TERN
-_WITHOUT_ALIAS
 .mat

resolve Encryptor reference on the fly