/*
* Copyright (C) 2016 Peng fei Pan <sky@xiaopan.me>
*
* 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 me.xiaopan.sketch.request;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import me.xiaopan.sketch.SLogType;
import me.xiaopan.sketch.SLog;
/**
* 顺风车管理器,主要用于解决重复下载、重复加载
* <p>
* 对于相同的请求(不同类型条件不一样),只要第一个请求执行完毕了,后续请求可以直接使用第一个请求的结果,那么我们可以将所有后续的请求都绑定在第一个请求上,
* 等第一个请求执行完毕后直接将结果交给后续请求处理即可,对于这样的情况我们称之为顺风车
*/
public class FreeRideManager {
private static final String LOG_NAME = "FreeRideManager";
private final Object displayFreeRideProviderMapLock = new Object();
private final Object downloadFreeRideProviderMapLock = new Object();
private Map<String, DisplayFreeRide> displayFreeRideProviderMap;
private Map<String, DownloadFreeRide> downloadFreeRideProviderMap;
/**
* 成为显示顺风车主
*/
public void registerDisplayFreeRideProvider(DisplayFreeRide provider) {
if (!provider.canByDisplayFreeRide()) {
return;
}
synchronized (displayFreeRideProviderMapLock) {
if (displayFreeRideProviderMap == null) {
synchronized (this) {
if (displayFreeRideProviderMap == null) {
displayFreeRideProviderMap = new WeakHashMap<String, DisplayFreeRide>();
}
}
}
displayFreeRideProviderMap.put(provider.getDisplayFreeRideKey(), provider);
SLog.v(SLogType.REQUEST, LOG_NAME, "display. register free ride provider. %s",
provider.getDisplayFreeRideLog());
}
}
/**
* 取消显示顺风车主身份并回调那些显示顺风车
*/
public void unregisterDisplayFreeRideProvider(DisplayFreeRide provider) {
if (!provider.canByDisplayFreeRide()) {
return;
}
// 取消顺风车主身份
DisplayFreeRide freeRideProvider = null;
synchronized (displayFreeRideProviderMapLock) {
if (displayFreeRideProviderMap != null) {
freeRideProvider = displayFreeRideProviderMap.remove(provider.getDisplayFreeRideKey());
if (freeRideProvider != null) {
SLog.w(SLogType.REQUEST, LOG_NAME, "display. unregister free ride provider. %s",
freeRideProvider.getDisplayFreeRideLog());
}
}
}
// 回调那些顺风车
if (freeRideProvider != null) {
Set<DisplayFreeRide> freeRideSet = freeRideProvider.getDisplayFreeRideSet();
if (freeRideSet == null || freeRideSet.size() == 0) {
return;
}
String providerId = freeRideProvider.getDisplayFreeRideLog();
for (DisplayFreeRide childFreeRide : freeRideSet) {
boolean success = childFreeRide.processDisplayFreeRide();
SLog.d(SLogType.REQUEST, LOG_NAME, "display. callback free ride. %s. %s <------ %s",
success ? "success" : "failed", childFreeRide.getDisplayFreeRideLog(), providerId);
}
freeRideSet.clear();
}
}
/**
* 坐个显示顺风车
*
* @param childFreeRide {@link DisplayFreeRide}
* @return 坐上了
*/
public boolean byDisplayFreeRide(DisplayFreeRide childFreeRide) {
if (!childFreeRide.canByDisplayFreeRide()) {
return false;
}
synchronized (displayFreeRideProviderMapLock) {
DisplayFreeRide freeRideProvider = null;
if (displayFreeRideProviderMap != null) {
freeRideProvider = displayFreeRideProviderMap.get(childFreeRide.getDisplayFreeRideKey());
}
if (freeRideProvider == null) {
return false;
}
freeRideProvider.byDisplayFreeRide(childFreeRide);
SLog.i(SLogType.REQUEST, LOG_NAME, "display. by free ride. %s ------> %s",
childFreeRide.getDisplayFreeRideLog(), freeRideProvider.getDisplayFreeRideLog());
return true;
}
}
/**
* 成为下载顺风车主
*/
public void registerDownloadFreeRideProvider(DownloadFreeRide provider) {
if (!provider.canByDownloadFreeRide()) {
return;
}
synchronized (downloadFreeRideProviderMapLock) {
if (downloadFreeRideProviderMap == null) {
synchronized (this) {
if (downloadFreeRideProviderMap == null) {
downloadFreeRideProviderMap = new WeakHashMap<String, DownloadFreeRide>();
}
}
}
downloadFreeRideProviderMap.put(provider.getDownloadFreeRideKey(), provider);
SLog.v(SLogType.REQUEST, LOG_NAME, "download. register free ride provider. %s",
provider.getDownloadFreeRideLog());
}
}
/**
* 取消下载顺风车主身份并回调那些下载顺风车
*/
public void unregisterDownloadFreeRideProvider(DownloadFreeRide provider) {
if (!provider.canByDownloadFreeRide()) {
return;
}
// 取消顺风车主身份
DownloadFreeRide freeRideProvider = null;
synchronized (downloadFreeRideProviderMapLock) {
if (downloadFreeRideProviderMap != null) {
freeRideProvider = downloadFreeRideProviderMap.remove(provider.getDownloadFreeRideKey());
if (freeRideProvider != null) {
SLog.w(SLogType.REQUEST, LOG_NAME, "download. unregister free ride provider. %s",
freeRideProvider.getDownloadFreeRideLog());
}
}
}
// 回调那些顺风车
if (freeRideProvider != null) {
Set<DownloadFreeRide> freeRideSet = freeRideProvider.getDownloadFreeRideSet();
if (freeRideSet == null || freeRideSet.size() == 0) {
return;
}
String providerId = freeRideProvider.getDownloadFreeRideLog();
for (DownloadFreeRide childFreeRide : freeRideSet) {
boolean success = childFreeRide.processDownloadFreeRide();
SLog.d(SLogType.REQUEST, LOG_NAME, "download. callback free ride. %s. %s <------ %s",
success ? "success" : "failed", childFreeRide.getDownloadFreeRideLog(), providerId);
}
freeRideSet.clear();
}
}
/**
* 坐个下载顺风车
*
* @param childFreeRide {@link DownloadFreeRide}
* @return 坐上了
*/
public boolean byDownloadFreeRide(DownloadFreeRide childFreeRide) {
if (!childFreeRide.canByDownloadFreeRide()) {
return false;
}
synchronized (downloadFreeRideProviderMapLock) {
DownloadFreeRide freeRideProvider = null;
if (downloadFreeRideProviderMap != null) {
freeRideProvider = downloadFreeRideProviderMap.get(childFreeRide.getDownloadFreeRideKey());
}
if (freeRideProvider == null) {
return false;
}
freeRideProvider.byDownloadFreeRide(childFreeRide);
SLog.i(SLogType.REQUEST, LOG_NAME, "download. by free ride. %s ------> %s",
childFreeRide.getDownloadFreeRideLog(), freeRideProvider.getDownloadFreeRideLog());
return true;
}
}
/**
* 显示顺风车
*/
public interface DisplayFreeRide {
/**
* 获取显示顺风车KEY
*/
String getDisplayFreeRideKey();
/**
* 获取日志
*/
String getDisplayFreeRideLog();
/**
* 是否可以使用显示顺风车功能(不同类型条件不一样)
*/
boolean canByDisplayFreeRide();
/**
* 让别人搭乘显示顺风车
*/
void byDisplayFreeRide(DisplayFreeRide request);
/**
* 获取显示顺风车集合
*/
Set<DisplayFreeRide> getDisplayFreeRideSet();
/**
* 执行结束,处理那些坐显示顺风车的请求
*
* @return 成功找到可以用的资源
*/
boolean processDisplayFreeRide();
}
/**
* 下载顺风车
*/
public interface DownloadFreeRide {
/**
* 获取下载顺风车KEY
*/
String getDownloadFreeRideKey();
/**
* 获取日志
*/
String getDownloadFreeRideLog();
/**
* 是否可以使用下载顺风车功能(不同类型条件不一样)
*/
boolean canByDownloadFreeRide();
/**
* 让别人搭乘下载顺风车
*/
void byDownloadFreeRide(DownloadFreeRide request);
/**
* 获取下载顺风车集合
*/
Set<DownloadFreeRide> getDownloadFreeRideSet();
/**
* 执行结束,处理那些坐下载顺风车的请求
*
* @return 成功找到可以用的资源
*/
boolean processDownloadFreeRide();
}
}