/*
MemoryCacheController.java
Copyright (c) 2014 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.event.cache;
import org.deviceconnect.android.event.Event;
import org.deviceconnect.android.event.EventError;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* イベントデータをメモリにキャッシュし、キャッシュの操作機能を提供する.
*
*
* @author NTT DOCOMO, INC.
*/
public class MemoryCacheController extends BaseCacheController {
/**
* イベントマップ. serviceId毎にイベントの種類をキーにイベント情報を管理する。
*
*/
private Map<String, Map<String, List<Event>>> mEventMap;
/**
* 空のサービスID用キー.
*/
private static final String NULL_SERVICE_ID = "__null";
/**
* 空のレシーバー用キー.
*/
private static final String NULL_RECEIVER_NAME = "";
/**
* メモリキャッシュコントローラーを生成する.
*/
public MemoryCacheController() {
mEventMap = new HashMap<>();
}
/**
* イベント情報からサービスIDを取得する.
* サービスIDが無い場合はnullを示す特殊な文字列を返す。
*
* @param event イベントデータ
* @return サービスID
*/
private String getServiceId(final Event event) {
String serviceId = event.getServiceId();
if (serviceId == null) {
serviceId = NULL_SERVICE_ID;
}
return serviceId;
}
/**
* イベント情報からレシーバー名を取得する.
* レシーバーが無い場合は空文字を返す。
*
* @param event イベント情報
* @return レシーバー名
*/
private String getReceiverName(final Event event) {
String receiver = event.getReceiverName();
if (receiver == null) {
receiver = NULL_RECEIVER_NAME;
}
return receiver;
}
@Override
public synchronized EventError addEvent(final Event event) {
if (!checkParameter(event)) {
return EventError.INVALID_PARAMETER;
}
String serviceId = getServiceId(event);
Map<String, List<Event>> events = mEventMap.get(serviceId);
if (events == null) {
events = new HashMap<>();
mEventMap.put(serviceId, events);
}
String path = event.getProfile();
if (event.getInterface() != null) {
path += event.getInterface();
}
if (event.getAttribute() != null) {
path += event.getAttribute();
}
List<Event> eventList = events.get(path);
if (eventList == null) {
eventList = new CopyOnWriteArrayList<>();
events.put(path, eventList);
}
String origin = event.getOrigin();
String receiver = getReceiverName(event);
for (Event e : eventList) {
if (compare(e.getOrigin(), origin) && compare(e.getReceiverName(), receiver)) {
// 登録済みの場合はアクセストークンを上書きする
e.setAccessToken(event.getAccessToken());
e.setUpdateDate(Utils.getCurreTimestamp());
return EventError.NONE;
}
}
event.setCreateDate(Utils.getCurreTimestamp());
event.setUpdateDate(Utils.getCurreTimestamp());
eventList.add(event);
return EventError.NONE;
}
@Override
public synchronized EventError removeEvent(final Event event) {
if (!checkParameter(event)) {
return EventError.INVALID_PARAMETER;
}
String serviceId = getServiceId(event);
Map<String, List<Event>> events = mEventMap.get(serviceId);
if (events == null) {
return EventError.NOT_FOUND;
}
String path = event.getProfile();
if (event.getInterface() != null) {
path += event.getInterface();
}
if (event.getAttribute() != null) {
path += event.getAttribute();
}
List<Event> eventList = events.get(path);
if (eventList == null) {
return EventError.NOT_FOUND;
}
String origin = event.getOrigin();
String receiver = getReceiverName(event);
for (Event e : eventList) {
if (compare(e.getOrigin(), origin) && compare(e.getReceiverName(), receiver)) {
eventList.remove(e);
if (eventList.size() == 0) {
events.remove(path);
}
return EventError.NONE;
}
}
return EventError.NOT_FOUND;
}
@Override
public synchronized Event getEvent(final String serviceId, final String profile, final String inter,
final String attribute, final String origin, final String receiver) {
Event event = null;
String tmpReceiver = receiver;
if (tmpReceiver == null) {
tmpReceiver = NULL_RECEIVER_NAME;
}
do {
List<Event> eventList = getEvents(serviceId, profile, inter, attribute);
if (eventList == null) {
break;
}
for (Event e : eventList) {
if (compare(e.getOrigin(), origin) && compare(e.getReceiverName(), tmpReceiver)) {
event = e;
break;
}
}
} while (false);
return event;
}
@Override
public synchronized List<Event> getEvents(final String serviceId, final String profile,
final String inter, final String attribute) {
String tmpServiceId = serviceId;
if (serviceId == null) {
tmpServiceId = NULL_SERVICE_ID;
}
Map<String, List<Event>> events = mEventMap.get(tmpServiceId);
if (events == null) {
return new ArrayList<>();
}
String path = profile;
if (inter != null) {
path += inter;
}
if (attribute != null) {
path += attribute;
}
List<Event> res = events.get(path);
if (res == null) {
return new ArrayList<>();
}
return res;
}
@Override
public synchronized List<Event> getEvents(final String origin) {
List<Event> result = new ArrayList<>();
for (Entry<String, Map<String, List<Event>>> entry : mEventMap.entrySet()) {
for (Entry<String, List<Event>> events : entry.getValue().entrySet()) {
for (Event event : events.getValue()) {
if (origin.equals(event.getOrigin())) {
result.add(event);
}
}
}
}
return result;
}
@Override
public void flush() {
// do nothing.
}
@Override
public synchronized boolean removeAll() {
mEventMap.clear();
return mEventMap.size() == 0;
}
private boolean compare(final String s1, final String s2) {
return (s1 == null && s2 == null) || s1!= null && s1.equals(s2);
}
/**
* イベントデータのキャッシュオブジェクトを取得する.
* Map<serviceId, Map<profile+interface+attribute, List<Event>>>。
*
* @return キャッシュ
*/
protected synchronized Map<String, Map<String, List<Event>>> getCache() {
return mEventMap;
}
/**
* キャッシュを設定する.
* nullの場合設定されない。
*
* @param cache キャッシュ
*/
protected synchronized void setCache(final Map<String, Map<String, List<Event>>> cache) {
if (cache != null) {
mEventMap = cache;
}
}
@Override
public synchronized boolean removeEvents(final String origin) {
if (origin == null) {
throw new IllegalArgumentException("origin is null.");
}
for (Entry<String, Map<String, List<Event>>> entry : mEventMap.entrySet()) {
for (Entry<String, List<Event>> events : entry.getValue().entrySet()) {
List<Event> removes = new ArrayList<>();
for (Event event : events.getValue()) {
if (origin.equals(event.getOrigin())) {
removes.add(event);
}
}
if (removes.size() != 0) {
events.getValue().removeAll(removes);
}
}
}
return true;
}
}