class AkCollatorFactory {

    public static AkCollator getAkCollator(final String scheme) {
        if (mode == Mode.DISABLED || scheme == null) {
            return UCS_BINARY_COLLATOR;
        }

        if (scheme.equalsIgnoreCase(UCS_BINARY)) {
            return mapToBinary(scheme);
        }

        SoftReference<AkCollator> ref = collatorMap.get(scheme);
        if (ref != null) {
            AkCollator akCollator = ref.get();
            if (akCollator != null) {
                cacheHits++;
                return akCollator;
            }
        }

        synchronized (collatorMap) {

            Integer collationId = schemeToIdMap.get(scheme);
            if (collationId == null) {
                collationId = collationIdGenerator.incrementAndGet();
            }

            final AkCollator akCollator;
            try {
                akCollator = new AkCollatorICU(scheme, collationId);
            } catch (InvalidCollationSchemeException | UnsupportedCollationException e) {
                if (mode == Mode.LOOSE) {
                    return mapToBinary(scheme);
                }
                throw e;
            }

            ref = new SoftReference<>(akCollator);
            collatorMap.put(scheme, ref);
            collationIdMap.put(collationId, ref);
            schemeToIdMap.put(scheme, collationId);

            return akCollator;
        }
    }

}