/** * 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 org.deephacks.confit.internal.jpa; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import org.deephacks.confit.model.Bean; import org.deephacks.confit.model.BeanId; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * Beans are connected by references as a graph. * * Query for beans begin by finding references for each level (i.e depth) * of beans. When list references are found, a final query for list bean's * properties is made. * * The purpose of this class is to both collect and cache data from these * queries. * * This helps removing redundant queries and assembling properties and * references into (a graph of) beans when list queries are finished. * * @author Kristoffer Sjogren */ public class JpaBeanQueryAssembler { /** * Contains the bean ids of the beans that were queries for. */ private Set<BeanId> beansQuery = new HashSet<>(); /** * Contain list beans references. */ private Multimap<BeanId, JpaRef> refs = ArrayListMultimap.create(); /** * Contain list beans that have been found as part of the query. */ private Map<BeanId, Bean> beans = new HashMap<>(); /** * Beans we want to find and initalize. */ public JpaBeanQueryAssembler(Set<BeanId> query) { this.beansQuery = query; } /** * Add properties to appropriate bean found from a partial * query of bean properties. */ public void addProperties(List<JpaProperty> queryProperties) { for (JpaProperty prop : queryProperties) { Bean bean = putIfAbsent(prop.getId()); if (!JpaProperty.BEAN_MARKER_PROPERTY_NAME.equals(prop.getPropertyName())) { bean.addProperty(prop.getPropertyName(), prop.getValue()); } } } /** * Add references found from a partial query of bean references. */ public void addRefs(Multimap<BeanId, JpaRef> queryRefs) { refs.putAll(queryRefs); for (BeanId id : refs.keySet()) { putIfAbsent(id); for (JpaRef ref : refs.get(id)) { putIfAbsent(ref.getTarget()); } } } /** * Add references found from a partial query of bean references. */ public void addRefs(Set<BeanId> queryRefs) { for (BeanId id : queryRefs) { putIfAbsent(id); } } /** * Return list bean ids that the assembler is currently aware of. */ public Set<BeanId> getIds() { Set<BeanId> ids = new HashSet<>(); ids.addAll(beansQuery); ids.addAll(beans.keySet()); return ids; } /** * Check if the assembler already is aware of a particular * bean. */ public boolean contains(BeanId id) { return beans.containsKey(id); } /** * Add a empty bean based on id if it does not already exist. */ private Bean putIfAbsent(BeanId id) { Bean bean = beans.get(id); if (bean == null) { bean = Bean.create(id); beans.put(id, bean); } return bean; } /** * Assemble beans and initalize their properties and references * from what have been provided. * * @return the beans that were provided in the inital query. */ public List<Bean> assembleBeans() { connectReferences(); if (beansQuery.size() == 0) { // if no specific beans where requested (such as query for a // specific schema) return what is available. return new ArrayList<>(beans.values()); } List<Bean> initalQuery = new ArrayList<>(); for (BeanId id : beansQuery) { Bean bean = beans.get(id); if (bean != null) { initalQuery.add(beans.get(id)); } } return initalQuery; } /** * Assemble beans and initalize references from what have been provided. */ private void connectReferences() { // ready to associate initalized beans with references for (Bean bean : beans.values()) { for (JpaRef ref : refs.get(bean.getId())) { BeanId target = ref.getTarget(); Bean targetBean = beans.get(target); target.setBean(targetBean); bean.addReference(ref.getPropertyName(), target); } } } }