/**
* personium.io
* Copyright 2014 FUJITSU LIMITED
*
* 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 com.fujitsu.dc.core.model.impl.es.odata;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.odata4j.core.OProperties;
import org.odata4j.core.OProperty;
import com.fujitsu.dc.common.es.response.DcSearchHits;
import com.fujitsu.dc.core.model.impl.es.QueryMapFactory;
import com.fujitsu.dc.core.model.impl.es.accessor.EntitySetAccessor;
import com.fujitsu.dc.core.model.impl.es.doc.OEntityDocHandler;
import com.fujitsu.dc.core.odata.NavigationTargetKeyProperty;
import com.fujitsu.dc.core.rs.odata.AbstractODataResource;
/**
* NavigationTargetKeyPropertyクラスのES実装.
*/
public class EsNavigationTargetKeyProperty implements NavigationTargetKeyProperty {
/** EntityType. */
private String type;
/** cellId. */
private String cellId;
/** boxId. */
private String boxId;
/** nodeId. */
private String nodeId;
/** staticフィールドの検索項目. */
private Map<String, String> statics = new HashMap<String, String>();
/** linkフィールドの検索項目. */
private Map<String, String> links = new HashMap<String, String>();
/** 推移先NTKP. */
private EsNavigationTargetKeyProperty shiftNtkp;
/** Property情報. */
private Set<OProperty<?>> properties = new HashSet<OProperty<?>>();
/**
* propertiesのセッター.
* @param properties properties
*/
public void setProperties(Set<OProperty<?>> properties) {
this.properties = properties;
}
/** ODataProducer情報. */
private EsODataProducer odataProducer;
/**
* コンストラクタ.
* @param cellId CellId
* @param boxId boxId
* @param nodeId nodeId
* @param type タイプ
* @param odataProducer odataProducer
*/
public EsNavigationTargetKeyProperty(String cellId,
String boxId,
String nodeId,
String type,
EsODataProducer odataProducer) {
this.cellId = cellId;
this.boxId = boxId;
this.nodeId = nodeId;
this.type = type;
this.odataProducer = odataProducer;
}
/**
* NavigationTargetKeyPropertyを検索する.
* @return リンク情報のTypeとIDのHashMap
*/
private Map<String, String> search() {
Map<String, Object> filter = getSearchQuery();
// 検索の実行
EntitySetAccessor esType = odataProducer.getAccessorForEntitySet(type);
DcSearchHits sHits = esType.search(filter).hits();
Map<String, String> link = new HashMap<String, String>();
if (sHits.getCount() == 0) {
// 存在していなければ、例外をあげる
String value = null;
for (Map.Entry<String, String> ent : statics.entrySet()) {
value = ent.getValue();
}
if (AbstractODataResource.isDummy(value)) {
link.put(type, AbstractODataResource.DUMMY_KEY);
} else {
throw new NTKPNotFoundException(value);
}
} else {
// {"type" : "id情報"}の形式で検索結果を返却する
link.put(type, sHits.getAt(0).getId());
}
return link;
}
/**
* 検索クエリー取得する.
* @return 検索クエリー
*/
private Map<String, Object> getSearchQuery() {
// Staticフィールドの検索クエリを組み立てる
List<Map<String, Object>> terms = new ArrayList<Map<String, Object>>();
if (!statics.isEmpty()) {
for (Map.Entry<String, String> ent : statics.entrySet()) {
terms.add(QueryMapFactory.termQuery(OEntityDocHandler.KEY_STATIC_FIELDS + "." + ent.getKey()
+ ".untouched", ent.getValue()));
}
}
// Linkフィールドの検索クエリを組み立てる
if (!links.isEmpty()) {
for (Map.Entry<String, String> ent : links.entrySet()) {
String linkKey = OEntityDocHandler.KEY_LINK + "." + ent.getKey();
if (AbstractODataResource.isDummy(ent.getValue())) {
// ダミーキーの場合はリンクのNull検索クエリを組み立てる
terms.add(QueryMapFactory.missingFilter(linkKey));
} else {
terms.add(QueryMapFactory.termQuery(linkKey, ent.getValue()));
}
}
}
List<Map<String, Object>> implicitConditions = new ArrayList<Map<String, Object>>();
// NodeIDを検索条件に指定
if (nodeId != null) {
implicitConditions.add(QueryMapFactory.termQuery(OEntityDocHandler.KEY_NODE_ID, nodeId));
}
// BoxIdを検索条件に指定
if (boxId != null) {
implicitConditions.add(QueryMapFactory.termQuery(OEntityDocHandler.KEY_BOX_ID, boxId));
}
// CellIDを検索条件に指定
if (cellId != null) {
implicitConditions.add(QueryMapFactory.termQuery(OEntityDocHandler.KEY_CELL_ID, cellId));
}
Map<String, Object> query = QueryMapFactory.filteredQuery(null, QueryMapFactory.mustQuery(implicitConditions));
Map<String, Object> filter = new HashMap<String, Object>();
filter.put("version", true);
if (!terms.isEmpty()) {
filter.put("filter", QueryMapFactory.andFilter(terms));
}
filter.put("query", query);
return filter;
}
/**
* プロパティー情報を解析する.
*/
private void analyzeProperties() {
for (OProperty<?> property : properties) {
HashMap<String, String> ntkp = AbstractODataResource.convertNTKP(property.getName());
if (ntkp == null) {
// staticフィールドの検索条件
statics.put(property.getName(), (String) property.getValue());
} else {
// linksフィールドの検索条件
if (shiftNtkp == null) {
shiftNtkp = new EsNavigationTargetKeyProperty(cellId, boxId, nodeId, ntkp.get("entityType"),
odataProducer);
}
// OPropertyを組み立てて、追加する
OProperty<?> newProperty = OProperties.string(ntkp.get("propName"), (String) property.getValue());
shiftNtkp.properties.add(newProperty);
}
}
if (shiftNtkp != null) {
links = shiftNtkp.recursiveSearch();
}
}
/**
* NTKPの推移を再帰的に検索して、リンク情報のTypeとIDのHashMapを返却する.
* @return リンク情報のTypeとIDのHashMap
*/
private Map<String, String> recursiveSearch() {
analyzeProperties();
return search();
}
/**
* NavigationTargetKeyPropertyの情報から、リンク情報のTypeとIDのEntryを取得する.
* @return リンク情報のTypeとIDのEntry
*/
@Override
public Map.Entry<String, String> getLinkEntry() {
analyzeProperties();
if (links.isEmpty()) {
return null;
}
// ダミーキーが設定されている場合はリンク情報無し
Map.Entry<String, String> entry = links.entrySet().iterator().next();
if (AbstractODataResource.isDummy(entry.getValue())) {
return null;
}
return entry;
}
/**
* NavigationTargetKeyPropertyを解析して、NTKPを検索するクエリーを取得する.
* @return NTKP検索クエリー
*/
@Override
public Map<String, Object> getNtkpSearchQuery() {
analyzeProperties();
return getSearchQuery();
}
/**
* NTKPNotFoundException.
*/
@SuppressWarnings("serial")
public static class NTKPNotFoundException extends RuntimeException {
/**
* コンストラクタ.
* @param msg msg.
*/
public NTKPNotFoundException(String msg) {
super(msg);
}
}
}