001package io.ebeanservice.docstore.api.mapping; 002 003import io.ebean.annotation.DocMapping; 004import io.ebean.annotation.DocStore; 005import io.ebean.text.PathProperties; 006import io.ebean.util.SplitName; 007 008import java.util.LinkedHashMap; 009import java.util.Map; 010import java.util.Stack; 011 012/** 013 * Builds the DocumentMapping for a given bean type. 014 */ 015public final class DocMappingBuilder { 016 017 private final PathProperties paths; 018 private final DocStore docStore; 019 private final Stack<DocPropertyMapping> properties = new Stack<>(); 020 private final Map<String, DocPropertyMapping> map = new LinkedHashMap<>(); 021 022 /** 023 * Create with the document structure paths and docStore deployment annotation. 024 */ 025 public DocMappingBuilder(PathProperties paths, DocStore docStore) { 026 this.paths = paths; 027 this.docStore = docStore; 028 this.properties.push(new DocPropertyMapping()); 029 } 030 031 /** 032 * Return true if the property is included in the document. 033 */ 034 public boolean includesProperty(String prefix, String name) { 035 return paths.includesProperty(prefix, name); 036 } 037 038 /** 039 * Return true if the path is included in the document. 040 */ 041 public boolean includesPath(String prefix, String name) { 042 return paths.includesProperty(prefix, name); 043 } 044 045 /** 046 * Add the property mapping. 047 */ 048 public void add(DocPropertyMapping docMapping) { 049 DocPropertyMapping currentParent = properties.peek(); 050 currentParent.addChild(docMapping); 051 052 String parentName = currentParent.name(); 053 String fullName = SplitName.add(parentName, docMapping.name()); 054 map.put(fullName, docMapping); 055 } 056 057 /** 058 * Push the nested object or list onto the properties stack. 059 */ 060 public void push(DocPropertyMapping nested) { 061 properties.push(nested); 062 } 063 064 /** 065 * Pop the nested object or list off the properties stack. 066 */ 067 public void pop() { 068 properties.pop(); 069 } 070 071 /** 072 * Apply any override mappings from the top level docStore annotation. 073 */ 074 public void applyMapping() { 075 for (DocMapping docMapping : docStore.mapping()) { 076 applyFieldMapping(docMapping); 077 } 078 } 079 080 private void applyFieldMapping(DocMapping docMapping) { 081 DocPropertyMapping mapping = map.get(docMapping.name()); 082 if (mapping == null) { 083 throw new IllegalStateException("DocMapping for [" + docMapping.name() + "] but property not included in document?"); 084 } 085 mapping.apply(docMapping); 086 } 087 088 /** 089 * Collect the mapping of properties to 'raw' properties for those marked as sortable. 090 */ 091 public Map<String, String> collectSortable() { 092 DocPropertyMapping peek = properties.peek(); 093 SortableVisitor visitor = new SortableVisitor(); 094 peek.visit(visitor); 095 return visitor.sortableMap(); 096 } 097 098 /** 099 * Create the document mapping. 100 */ 101 public DocumentMapping create(String queueId, String indexName, String indexType) { 102 int shards = docStore.shards(); 103 int replicas = docStore.replicas(); 104 DocPropertyMapping root = properties.peek(); 105 return new DocumentMapping(queueId, indexName, indexType, paths, root, shards, replicas); 106 } 107 108 109 /** 110 * Find sortable properties to build the mapping to 'raw' properties. 111 */ 112 private static class SortableVisitor extends DocPropertyAdapter { 113 114 private final Map<String, String> sortableMap = new LinkedHashMap<>(); 115 116 @Override 117 public void visitProperty(DocPropertyMapping property) { 118 DocPropertyOptions options = property.options(); 119 if (options != null && options.isSortable()) { 120 String fullPath = pathStack.peekFullPath(property.name()); 121 sortableMap.put(fullPath, fullPath + ".raw"); 122 } 123 } 124 125 private Map<String, String> sortableMap() { 126 return sortableMap; 127 } 128 } 129}