1   /*
2    * Copyright 2015 FBK-irst.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package eu.fbk.knowledgestore.elastic;
17  
18  import eu.fbk.knowledgestore.data.Record;
19  import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
20  import org.elasticsearch.cluster.metadata.MappingMetaData;
21  import org.elasticsearch.common.collect.ImmutableOpenMap;
22  import org.elasticsearch.common.hppc.cursors.ObjectCursor;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  
26  import java.io.IOException;
27  import java.util.Date;
28  import java.util.HashMap;
29  import java.util.Map;
30  import java.util.Set;
31  
32  /**
33   * saves the mapping and allows to query what kind of data is behind a given property name.
34   * @author enrico
35   */
36  public class MappingHandler{
37      private static final Logger LOGGER = LoggerFactory.getLogger(MappingHandler.class);    
38      HashMap<String, Class<?>> mapper;
39     
40      /**
41       * saves the mappings: property name : class of the value.
42       * @param mappings object that contains the mappings of all the types in all the indexes.
43       * @throws IOException 
44       */
45      MappingHandler(GetMappingsResponse mappings) throws IOException{
46          mapper = new HashMap<>();
47          
48          for(ObjectCursor<String> keyRoot : mappings.getMappings().keys()){
49              ImmutableOpenMap<String, MappingMetaData> openMap = mappings.getMappings().get(keyRoot.value);
50              for(ObjectCursor<String> key : openMap.keys()){
51                  addMappings(openMap.get(key.value).getSourceAsMap());
52              }
53          }
54      }
55      /**
56       * return the Class of the value for the specified property.
57       * @param propName name of the property
58       * @return 
59       */
60       public Class<?> getValueClass(String propName){
61           Class<?> res = mapper.get(propName);
62           if(res == null){
63               LOGGER.debug("undefined property");
64               throw new IllegalArgumentException("undefined property: " + propName);
65           }
66          return res;
67      }
68      
69      private void addMappings(Map<String, Object> map){
70          Map typeMapping = (Map)map.get("properties"); //get the properties.
71          for(Object key : typeMapping.keySet()){ //for every property
72              Map typeMappingValue = (Map)typeMapping.get(key); //set of settings of the property.
73              if(typeMappingValue.keySet().contains("type")){ //if contains type it's not a nested record.
74                  Class<?> propertyValueClass = fromStringToClass(typeMappingValue.get("type"));
75  //               LOGGER.debug("\tadding: " + key + " -> " + propertyValueClass);
76                  mapper.put((String)key, propertyValueClass);
77              }else{ //if it's a nested record.
78                  mapper.put((String)key, Record.class);
79                  addMappings(typeMappingValue);
80              }
81          }
82      }
83      
84      public Set<String> getKeys(){
85          return mapper.keySet();
86      }
87      
88      private Class<?> fromStringToClass(Object str){
89          Class<?> res = null;
90          String stringClass = ((String)str).toLowerCase();
91          switch((String)str){
92              case "string":
93                  res = String.class;
94                  break;
95              case "integer":
96                  res = Integer.class;
97                  break;
98              case "byte":
99                  res = Byte.class;
100                 break;
101             case "short":
102                 res = Short.class;
103                 break;
104             case "long":
105                 res = Long.class;
106                 break;
107             case "float":
108                 res = Float.class;
109                 break;
110             case "double":
111                 res = Double.class;
112                 break;
113             case "date":
114                 res = Date.class;
115                 break;
116             case "boolean":
117                 res = Boolean.class;
118                 break;
119             case "binary":
120                 res = byte[].class;
121                 break;
122             default:
123                 throw new IllegalArgumentException("unknown class: " + stringClass + " in the mapping");
124         }
125         return res;
126     }
127 }