/** * * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); You may not * use this file except in compliance with the License. You may obtain a copy of * the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.speedment.generator.translator.internal.component; import com.speedment.common.codegen.model.ClassOrInterface; import com.speedment.common.injector.Injector; import com.speedment.common.injector.annotation.Inject; import com.speedment.common.mapstream.MapStream; import com.speedment.generator.translator.JavaClassTranslator; import com.speedment.generator.translator.Translator; import com.speedment.generator.translator.TranslatorConstructor; import com.speedment.generator.translator.TranslatorDecorator; import com.speedment.generator.translator.component.CodeGenerationComponent; import com.speedment.generator.translator.exception.SpeedmentTranslatorException; import com.speedment.runtime.config.trait.HasMainInterface; import com.speedment.runtime.config.trait.HasName; import java.util.List; import java.util.Map; import static java.util.Objects.requireNonNull; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; public final class CodeGenerationComponentImpl implements CodeGenerationComponent { private @Inject Injector injector; private final Map<Class<? extends HasMainInterface>, Map<String, TranslatorSettings<?, ?>>> map; public CodeGenerationComponentImpl() { map = new ConcurrentHashMap<>(); } @SuppressWarnings("unchecked") @Override public <DOC extends HasName & HasMainInterface, T extends ClassOrInterface<T>> void put(Class<DOC> docType, Class<T> modelType, String key, TranslatorConstructor<DOC, T> constructor) { aquireTranslatorSettings(docType, modelType, key).setConstructor(constructor); } @Override public <DOC extends HasName & HasMainInterface, T extends ClassOrInterface<T>> void add(Class<DOC> docType, Class<T> modelType, String key, TranslatorDecorator<DOC, T> decorator) { aquireTranslatorSettings(docType, modelType, key).decorators().add(decorator); } @Override public <DOC extends HasName & HasMainInterface, T extends ClassOrInterface<T>> void remove(Class<DOC> docType, String key) { aquireTranslatorSettings(docType, null, key).setConstructor(null); } private <DOC extends HasName & HasMainInterface, T extends ClassOrInterface<T>> TranslatorSettings<DOC, T> aquireTranslatorSettings(Class<DOC> docType, Class<T> modelType, String key) { @SuppressWarnings("unchecked") final TranslatorSettings<DOC, T> result = (TranslatorSettings<DOC, T>) map .computeIfAbsent(docType, s -> new ConcurrentHashMap<>() ).computeIfAbsent(key, k -> new TranslatorSettings<>(k)); return result; } @Override public <DOC extends HasName & HasMainInterface> Stream<? extends Translator<DOC, ?>> translators(DOC document) { return translators(document, s -> true); } @Override public Stream<String> translatorKeys() { return map.values().stream() .flatMap(m -> MapStream.of(m).filterValue(s -> s.constructor != null).keys()) .distinct(); } @Override @SuppressWarnings("unchecked") public <DOC extends HasName & HasMainInterface, T extends ClassOrInterface<T>> Translator<DOC, T> findTranslator(DOC document, Class<T> modelType, String key) { return translators(document, key::equals) .findAny() .map(translator -> (Translator<DOC, T>) translator) .orElseThrow(noTranslatorFound(document, key)); } @SuppressWarnings("unchecked") private <DOC extends HasName & HasMainInterface> Stream<? extends Translator<DOC, ?>> translators(DOC document, Predicate<String> nameFilter) { return MapStream.of(map) .filterKey(c -> c.isInstance(document)) .values() .flatMap(m -> MapStream.of(m).filterKey(nameFilter).values()) .map(s -> (TranslatorSettings<DOC, ?>) s) .filter(s -> s != null) .filter(s -> s.getConstructor() != null) .map(settings -> settings.createDecorated(injector, document)); } private static Supplier<SpeedmentTranslatorException> noTranslatorFound(HasMainInterface doc, String key) { return () -> new SpeedmentTranslatorException( "Found no translator with key '" + key + "' for document '" + doc.mainInterface().getSimpleName() + "'." ); } private final static class TranslatorSettings<DOC extends HasName & HasMainInterface, T extends ClassOrInterface<T>> { private final String key; private final List<TranslatorDecorator<DOC, T>> decorators; private TranslatorConstructor<DOC, T> constructor; public TranslatorSettings(String key) { this.key = requireNonNull(key); this.decorators = new CopyOnWriteArrayList<>(); } public String key() { return key; } public TranslatorConstructor<DOC, T> getConstructor() { return constructor; } public void setConstructor(TranslatorConstructor<DOC, T> constructor) { this.constructor = constructor; } public List<TranslatorDecorator<DOC, T>> decorators() { return decorators; } public JavaClassTranslator<DOC, T> createDecorated(Injector injector, DOC document) { @SuppressWarnings("unchecked") final JavaClassTranslator<DOC, T> translator = (JavaClassTranslator<DOC, T>) getConstructor().apply(document); injector.inject(translator); decorators.stream() .map(injector::inject) .forEachOrdered(dec -> dec.apply(translator)); return translator; } } }