class ComponentFactoryService {

	public static <T extends ComponentFactory> T find(Class<T> factoryClass, Map<String, String> propertyMap) {
		List<T> all = TableFactoryService.findAll(factoryClass, propertyMap);

		List<T> filtered = all.stream().filter(factory -> {
			Map<String, String> optionalContext = factory.optionalContext();
			return optionalContext.entrySet().stream().allMatch(entry -> {
					String property = propertyMap.get(entry.getKey());
					if (property != null) {
						return property.equals(entry.getValue());
					} else {
						return true;
					}
				}
			);
		}).collect(Collectors.toList());

		if (filtered.size() > 1) {
			throw new AmbiguousTableFactoryException(
				filtered,
				factoryClass,
				new ArrayList<>(all),
				propertyMap
			);
		} else if (filtered.isEmpty()) {
			throw new NoMatchingTableFactoryException(
				"No factory supports the additional filters.",
				factoryClass,
				new ArrayList<>(all),
				propertyMap);
		} else {
			return filtered.get(0);
		}
	}

}