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