Package com.ajjpj.amapper.core.impl

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

package com.ajjpj.amapper.core.impl;

import com.ajjpj.amapper.core.*;
import com.ajjpj.amapper.core.exclog.AMapperExceptionHandler;
import com.ajjpj.amapper.core.exclog.AMapperLogger;
import com.ajjpj.amapper.core.path.APath;
import com.ajjpj.amapper.core.tpe.AQualifiedSourceAndTargetType;
import com.ajjpj.amapper.core.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<RuntimeException>> 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<RuntimeException>> 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) {
        try {
            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);
            }
        } catch (Exception exc) {
            return AMapperExceptionHandler.onError(exc, path);
        }
    }

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

        try {
            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);
        } catch (Exception exc) {
            return AMapperExceptionHandler.onError(exc, path);
        }
    }

    @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;
            }
        });

        try {
            final AValueMappingDef<Object, Object, H> vm = valueMappings.expectedEntryFor(types, path);
            return vm.map(source, types, this, context);
        }
        catch(Exception exc) {
            return AMapperExceptionHandler.onError(exc, path);
        }
    }

    @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<RuntimeException>() {
            @Override public void apply() {
                logger.debug(new AStringFunction0() {
                    @Override
                    public String apply() {
                        return "processing deferred: " + types + " @ " + path;
                    }
                });

                try {
                    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());
                        }
                    }
                }
                catch (Exception exc) {
                    AMapperExceptionHandler.onError(exc, path);
                }
            }
        });
    }
}
TOP

Related Classes of com.ajjpj.amapper.core.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.