CodecRegistry { @VisibleForTesting void updateCoders(Iterable<RawErasureCoderFactory> coderFactories) { for (RawErasureCoderFactory coderFactory : coderFactories) { String codecName = coderFactory.getCodecName(); List<RawErasureCoderFactory> coders = coderMap.get(codecName); if (coders == null) { coders = new ArrayList<>(); coders.add(coderFactory); coderMap.put(codecName, coders); LOG.debug("Codec registered: codec = {}, coder = {}", coderFactory.getCodecName(), coderFactory.getCoderName()); } else { Boolean hasConflit = false; for (RawErasureCoderFactory coder : coders) { if (coder.getCoderName().equals(coderFactory.getCoderName())) { hasConflit = true; LOG.error("Coder {} cannot be registered because its coder name " + "{} has conflict with {}", coderFactory.getClass().getName(), coderFactory.getCoderName(), coder.getClass().getName()); break; } } if (!hasConflit) { if (coderFactory instanceof NativeRSRawErasureCoderFactory || coderFactory instanceof NativeXORRawErasureCoderFactory) { coders.add(0, coderFactory); } else { coders.add(coderFactory); } LOG.debug("Codec registered: codec = {}, coder = {}", coderFactory.getCodecName(), coderFactory.getCoderName()); } } } coderNameMap.clear(); for (Map.Entry<String, List<RawErasureCoderFactory>> entry : coderMap.entrySet()) { String codecName = entry.getKey(); List<RawErasureCoderFactory> coders = entry.getValue(); coderNameMap.put(codecName, coders.stream(). map(RawErasureCoderFactory::getCoderName). collect(Collectors.toList()).toArray(new String[0])); coderNameCompactMap.put(codecName, coders.stream(). map(RawErasureCoderFactory::getCoderName) .collect(Collectors.joining(", "))); } } private  CodecRegistry(); static CodecRegistry getInstance(); String[] getCoderNames(String codecName); List<RawErasureCoderFactory> getCoders(String codecName); Set<String> getCodecNames(); RawErasureCoderFactory getCoderByName(
      String codecName, String coderName); Map<String, String> getCodec2CoderCompactMap();  }
@Test public void testUpdateCoders() { class RSUserDefinedIncorrectFactory implements RawErasureCoderFactory { public RawErasureEncoder createEncoder(ErasureCoderOptions coderOptions) { return null; } public RawErasureDecoder createDecoder(ErasureCoderOptions coderOptions) { return null; } public String getCoderName() { return "rs_java"; } public String getCodecName() { return ErasureCodeConstants.RS_CODEC_NAME; } } List<RawErasureCoderFactory> userDefinedFactories = new ArrayList<>(); userDefinedFactories.add(new RSUserDefinedIncorrectFactory()); CodecRegistry.getInstance().updateCoders(userDefinedFactories); List<RawErasureCoderFactory> rsCoders = CodecRegistry.getInstance(). getCoders(ErasureCodeConstants.RS_CODEC_NAME); assertEquals(2, rsCoders.size()); assertTrue(rsCoders.get(0) instanceof NativeRSRawErasureCoderFactory); assertTrue(rsCoders.get(1) instanceof RSRawErasureCoderFactory); String[] rsCoderNames = CodecRegistry.getInstance(). getCoderNames(ErasureCodeConstants.RS_CODEC_NAME); assertEquals(2, rsCoderNames.length); assertEquals(NativeRSRawErasureCoderFactory.CODER_NAME, rsCoderNames[0]); assertEquals(RSRawErasureCoderFactory.CODER_NAME, rsCoderNames[1]); }