Package com.ajjpj.amapper.core2.impl

Source Code of com.ajjpj.amapper.core2.impl.AMapperWorkerImpl

package com.ajjpj.amapper.core2.impl;

import com.ajjpj.amapper.core2.*;
import com.ajjpj.amapper.core2.exclog.AMapperLogger;
import com.ajjpj.amapper.core2.path.APath;
import com.ajjpj.amapper.core2.tpe.AQualifiedSourceAndTargetType;
import com.ajjpj.amapper.core2.tpe.CanHandleSourceAndTargetCache;
import com.ajjpj.amapper.util.coll.AHashMap;
import com.ajjpj.amapper.util.coll.AMap;
import com.ajjpj.amapper.util.coll.AOption;
import com.ajjpj.amapper.util.func.AFunction0;
import com.ajjpj.amapper.util.func.AStringFunction0;
import com.ajjpj.amapper.util.func.AVoidFunction0;
import com.ajjpj.amapper.util.func.AVoidFunction1;

import java.util.Queue;

/**
* @author arno
*/
public class AMapperWorkerImpl<H> implements AMapperWorker<H> {
    private final CanHandleSourceAndTargetCache<AValueMappingDef<?,?,? super H>, AValueMappingDef<Object, Object, H>> valueMappings;
    private final CanHandleSourceAndTargetCache<AObjectMappingDef<?,?,? super H>, AObjectMappingDef<Object, Object, H>> objectMappings;
    private final AMapperLogger logger;
    private final H helpers;
    private final AIdentifierExtractor identifierExtractor;
    private final AContextExtractor contextExtractor;
    private final CanHandleSourceAndTargetCache<APreProcessor, APreProcessor> preProcessors;
    private final CanHandleSourceAndTargetCache<APostProcessor, APostProcessor> postProcessors;
    private final Queue<AVoidFunction0<Exception>> deferredWork;

    private final IdentityCache identityCache = new IdentityCache();

    public AMapperWorkerImpl(CanHandleSourceAndTargetCache<AValueMappingDef<?, ?, ? super H>, AValueMappingDef<Object, Object, H>> valueMappings,
                             CanHandleSourceAndTargetCache<AObjectMappingDef<?, ?, ? super H>, AObjectMappingDef<Object, Object, H>> objectMappings,
                             AMapperLogger logger, H helpers,
                             AIdentifierExtractor identifierExtractor, AContextExtractor contextExtractor,
                             CanHandleSourceAndTargetCache<APreProcessor, APreProcessor> preProcessor,
                             CanHandleSourceAndTargetCache<APostProcessor, APostProcessor> postProcessor,
                             Queue<AVoidFunction0<Exception>> deferredWork) {
        this.valueMappings = valueMappings;
        this.objectMappings = objectMappings;
        this.logger = logger;
        this.helpers = helpers;
        this.identifierExtractor = identifierExtractor;
        this.contextExtractor = contextExtractor;
        this.preProcessors = preProcessor;
        this.postProcessors = postProcessor;
        this.deferredWork = deferredWork;
    }

    @Override public AMapperLogger getLogger() {
        return logger;
    }

    @Override public H getHelpers() {
        return helpers;
    }

    @Override public AIdentifierExtractor getIdentifierExtractor() {
        return identifierExtractor;
    }

    @Override public AOption<Object> map(APath path, Object source, Object target, AQualifiedSourceAndTargetType types, AMap<String, Object> context) throws Exception {
        final AOption<AValueMappingDef<Object, Object, H>> vm = valueMappings.tryEntryFor(types);
        if(vm.isDefined()) {
            return AOption.some(vm.get().map(source, types, this, context));
        }
        else {
            return mapObject(path, source, target, types, context);
        }
    }

    @Override public AOption<Object> mapObject(final APath path, final Object sourceRaw, Object target, AQualifiedSourceAndTargetType types, AMap<String, Object> context) throws Exception {
        logger.debug (new AStringFunction0() {
            @Override
            public String apply() {
                return "map: " + sourceRaw + " @ " + path;
            }
        });

        final AObjectMappingDef<Object, Object, H> m = objectMappings.expectedEntryFor(types, path);
        final APreProcessor pre = preProcessors.tryEntryFor(types).getOrElse(APreProcessor.NO_PREPROCESSOR);
        final AOption<Object> preProcessed = pre.preProcess(sourceRaw, types);

        if(preProcessed.isEmpty()) {
            // preprocessor vetoed this mapping operation
            return AOption.none();
        }

        final Object source = preProcessed.get();
        final AOption<Object> cached = identityCache.get(source);
        if(cached.isDefined()) {
            return cached;
        }

        final AMap<String, Object> newContext = contextExtractor.withContext(context, sourceRaw, types.sourceType);
        final Object resultRaw = m.map(source, target, types, this, newContext, path);

        final Object result = postProcessors.tryEntryFor(types).getOrElse(APostProcessor.NO_POSTPROCESSOR).postProcess(resultRaw, types);

        if(m.isCacheable()) {
            identityCache.register(source, result, path);
        }

        return AOption.some(result);
    }

    @Override public Object mapValue(final APath path, final Object source, AQualifiedSourceAndTargetType types, AMap<String, Object> context) {
        logger.debug (new AStringFunction0() {
            @Override
            public String apply() {
                return "map: " + source + " @ " + path;
            }
        });
        final AValueMappingDef<Object, Object, H> vm = valueMappings.expectedEntryFor(types, path);
        return vm.map(source, types, this, context);
    }

    @Override public void mapDeferred(final APath path, final Object sourceRaw, final AFunction0<Object, Exception> target, final AQualifiedSourceAndTargetType types, final AVoidFunction1<Object, Exception> callback) {
        logger.debug (new AStringFunction0() {
            @Override public String apply() {
                return "map deferred: " + types + " @ " + path;
            }
        });

        deferredWork.add(new AVoidFunction0<Exception>() {
            @Override public void apply() throws Exception {
                logger.debug(new AStringFunction0() {
                    @Override
                    public String apply() {
                        return "processing deferred: " + types + " @ " + path;
                    }
                });

                final APreProcessor pre = preProcessors.tryEntryFor(types).getOrElse(APreProcessor.NO_PREPROCESSOR);
                final AOption<Object> preProcessed = pre.preProcess(sourceRaw, types);

                if(preProcessed.isEmpty()) {
                    return;
                }
                final Object source = preProcessed.get();

                final AOption<Object> prevTarget = identityCache.get(source);
                if(prevTarget.isDefined()) {
                    callback.apply(prevTarget.get());
                }
                else {
                    logger.deferredWithoutInitial(path); //TODO special treatment for collections etc. --> flag in the mapping def?
                    // create a new, empty context: context is accumulated only from parents to children
                    final AOption<Object> mapped = mapObject(path, source, target, types, AHashMap.<String, Object>empty());
                    if(mapped.isDefined()) {
                        callback.apply(mapped.get());
                    }
                }
            }
        });
    }
}
TOP

Related Classes of com.ajjpj.amapper.core2.impl.AMapperWorkerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.