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 for (DocMapping docMapping : docStore.mapping()) { 080 applyFieldMapping(docMapping); 081 } 082 } 083 084 private void applyFieldMapping(DocMapping docMapping) { 085 086 DocPropertyMapping mapping = map.get(docMapping.name()); 087 if (mapping == null) { 088 throw new IllegalStateException("DocMapping for [" + docMapping.name() + "] but property not included in document?"); 089 } 090 mapping.apply(docMapping); 091 } 092 093 /** 094 * Collect the mapping of properties to 'raw' properties for those marked as sortable. 095 */ 096 public Map<String, String> collectSortable() { 097 098 DocPropertyMapping peek = properties.peek(); 099 SortableVisitor visitor = new SortableVisitor(); 100 peek.visit(visitor); 101 102 return visitor.getSortableMap(); 103 } 104 105 /** 106 * Create the document mapping. 107 */ 108 public DocumentMapping create(String queueId, String indexName, String indexType) { 109 110 int shards = docStore.shards(); 111 int replicas = docStore.replicas(); 112 DocPropertyMapping root = properties.peek(); 113 return new DocumentMapping(queueId, indexName, indexType, paths, root, shards, replicas); 114 } 115 116 117 /** 118 * Find sortable properties to build the mapping to 'raw' properties. 119 */ 120 private static class SortableVisitor extends DocPropertyAdapter { 121 122 private Map<String, String> sortableMap = new LinkedHashMap<>(); 123 124 @Override 125 public void visitProperty(DocPropertyMapping property) { 126 127 DocPropertyOptions options = property.getOptions(); 128 if (options != null && options.isSortable()) { 129 String fullPath = pathStack.peekFullPath(property.getName()); 130 sortableMap.put(fullPath, fullPath + ".raw"); 131 } 132 } 133 134 private Map<String, String> getSortableMap() { 135 return sortableMap; 136 } 137 } 138}