class CombinedProperties implements Map<String, Object> {

    @Override
    public final Object get(Object key) {
        if (key == null) {
            return null;
        }

        final ComputedPropertyParameter computedPropertyParameter = new ComputedPropertyParameter((String) key);

        log.trace("Getting value for key [ {} ] from CombinedProperties", computedPropertyParameter.getCacheId());

        if (computedPropertyParameter.getName() == null) {
            return null;
        }

        Object result = null;

        final ComputedProperty computedProperty = computedProperties.get(computedPropertyParameter.getName());

        if (computedProperty != null) {
            if (computedProperty.isCachable() && cachedValues.containsKey(computedPropertyParameter.getCacheId())) {
                result = cachedValues.get(computedPropertyParameter.getCacheId());
                if (log.isDebugEnabled()) {
                    log.debug(String.format("Computed value [ %s -> %s ] using [ %s ] served from ComputedPropertyAccessor cache.", computedPropertyParameter.getCacheId(), result, computedProperty.getClass().getName()));
                }
            } else if (computedProperty.accepts(asset, request, computedPropertyParameter.getName())) {
                result = computedProperty.get(asset, request, computedPropertyParameter.getParameters());

                if (computedProperty.isCachable()) {
                    cachedValues.put(computedPropertyParameter.getCacheId(), result);
                }

                if (log.isDebugEnabled()) {
                    log.debug(String.format("Computed value [ %s -> %s ] using [ %s ] ", computedPropertyParameter.getCacheId(), result, computedProperty.getClass().getName()));
                }
            }
        }

        if (result == null && metaProperties != null) {
            result = metaProperties.get(computedPropertyParameter.getName());
        }

        if (result == null && assetProperties != null) {
            result = assetProperties.get(computedPropertyParameter.getName());
        }

        return result;
    }

    public  CombinedProperties(final List<ComputedProperty> computedProperties,
                              final SlingHttpServletRequest request,
                              final Asset asset);

}