Package at.molindo.esi4j.mapping.impl

Source Code of at.molindo.esi4j.mapping.impl.GenericTypeMapping

/**
* Copyright 2010 Molindo GmbH
*
* 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 at.molindo.esi4j.mapping.impl;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.get.GetField;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.Mapper.BuilderContext;
import org.elasticsearch.index.mapper.object.RootObjectMapper;
import org.elasticsearch.index.mapper.object.RootObjectMapper.Builder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHitField;

import at.molindo.esi4j.mapping.MappingSource;
import at.molindo.esi4j.mapping.ObjectSource;
import at.molindo.esi4j.mapping.TypeMapping;
import at.molindo.utils.collections.CollectionUtils;

import com.google.common.collect.Maps;

/**
* generic version of {@link TypeMapping}. All subclasses should extend this
* class instead of {@link TypeMapping} while it's generally better to use
* {@link TypeMapping} where the exact type of mapping is not known or not
* relevant
*
* @param <Type>
*            class of mapped type
* @param <Id>
*            class of mapped type's ID
*/
public abstract class GenericTypeMapping<Type, Id> extends TypeMapping {

  private final Class<Type> _typeClass;
  private final Class<Id> _idClass;

  private String _mapping;

  public GenericTypeMapping(String typeAlias, Class<Type> typeClass, Class<Id> idClass) {
    super(typeAlias);
    if (typeClass == null) {
      throw new NullPointerException("typeClass");
    }
    if (idClass == null) {
      throw new NullPointerException("idClass");
    }
    _typeClass = typeClass;
    _idClass = idClass;
  }

  @Override
  public final MappingSource getMappingSource() {
    try {
      if (_mapping == null) {
        Builder mapperBuilder = new RootObjectMapper.Builder(getTypeAlias());

        buildMapping(mapperBuilder);

        XContentBuilder contentBuilder = JsonXContent.contentBuilder();

        contentBuilder.startObject();
        mapperBuilder.build(new BuilderContext(null, new ContentPath())).toXContent(contentBuilder, null);
        contentBuilder.endObject();

        // cache mapping as string for easy debugging
        _mapping = contentBuilder.string();
      }
      return MappingSource.Builder.string(_mapping);
    } catch (IOException e) {
      throw new RuntimeException();
    }
  }

  @Override
  public ObjectSource getObjectSource(Object o) {
    try {
      return ObjectSource.Builder.builder(getContentBuilder(o));
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * public for testing.
   *
   * @return a JsonXContent builder
   */
  public final XContentBuilder getContentBuilder(Object o) throws IOException {
    XContentBuilder contentBuilder = JsonXContent.contentBuilder();
    write(contentBuilder, o);
    return contentBuilder;
  }

  public final void write(XContentBuilder contentBuilder, Object o) throws IOException {
    contentBuilder.startObject();

    // TODO why do we add the id to the document source?
    String id = getIdString(o);
    if (id != null) {
      // skip empty id for id generation
      contentBuilder.field(FIELD_ID).value(id);
    }

    writeObject(contentBuilder, cast(o));
    contentBuilder.endObject();
  }

  @Override
  public final Type read(GetResponse response) {
    return response.isExists() ? read(getSource(response)) : null;
  }

  @Override
  public final Type read(SearchHit hit) {
    return read(getSource(hit));
  }

  /**
   * @return map containing all properties of a {@link GetResponse}
   * @see #getSource(SearchHit)
   */
  protected Map<String, Object> getSource(GetResponse response) {
    Map<String, Object> map = response.getSource();
    if (map == null) {
      map = Maps.newHashMap();
      for (Entry<String, GetField> e : response.getFields().entrySet()) {
        List<?> values = e.getValue().getValues();
        if (!CollectionUtils.empty(values)) {
          map.put(e.getKey(), values.size() == 1 ? values.get(0) : values);
        }
      }
    }
    map.put(FIELD_INDEX, response.getIndex());
    map.put(FIELD_TYPE, response.getType());
    map.put(FIELD_ID, response.getId());
    if (response.getVersion() != -1) {
      map.put(FIELD_VERSION, response.getVersion());
    }
    return map;
  }

  /**
   * @return map containing all properties of a {@link SearchHit}
   * @see #getSource(GetResponse)
   */
  protected Map<String, Object> getSource(SearchHit hit) {
    Map<String, Object> map = hit.sourceAsMap();
    if (map == null) {
      map = Maps.newHashMap();
      for (Entry<String, SearchHitField> e : hit.getFields().entrySet()) {
        List<?> values = e.getValue().getValues();
        if (!CollectionUtils.empty(values)) {
          map.put(e.getKey(), values.size() == 1 ? values.get(0) : values);
        }
      }
    }
    map.put(FIELD_INDEX, hit.getIndex());
    map.put(FIELD_TYPE, hit.getType());
    map.put(FIELD_ID, hit.getId());
    if (hit.getVersion() != -1) {
      map.put(FIELD_VERSION, hit.getVersion());
    }
    return map;
  }

  @Override
  public Class<Type> getTypeClass() {
    return _typeClass;
  }

  @Override
  public Class<Id> getIdClass() {
    return _idClass;
  }

  protected Type cast(Object o) {
    return getTypeClass().cast(o);
  }

  protected Id castId(Object o) {
    return getIdClass().cast(o);
  }

  @Override
  public final boolean isFiltered(Object entity) {
    return filter(cast(entity));
  }

  @Override
  public final Id getId(Object o) {
    return id(cast(o));
  }

  @Override
  public Long getVersion(Object o) {
    return version(cast(o));
  }

  protected boolean filter(Type o) {
    return false;
  }

  @Override
  public final String toIdString(Object id) {
    return toString(castId(id));
  }

  public abstract String toString(Id id);

  @Override
  public abstract Id toId(String id);

  /**
   * get Id from object
   *
   * @see #getId(Object)
   */
  protected abstract Id id(Type o);

  /**
   * get version from object
   *
   * @see #getVersion(Object)
   */
  protected abstract Long version(Type o);

  protected abstract void buildMapping(RootObjectMapper.Builder mapperBuilder) throws IOException;

  protected abstract void writeObject(XContentBuilder contentBuilder, Type o) throws IOException;

  /**
   * read object from source. Publicly accessible for testing
   */
  public abstract Type read(Map<String, Object> source);

}
TOP

Related Classes of at.molindo.esi4j.mapping.impl.GenericTypeMapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.