/*
* Copyright 2012 astamuse company,Ltd.
*
* 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.astamuse.asta4d.web.dispatch;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import com.astamuse.asta4d.Context;
import com.astamuse.asta4d.web.WebApplicationConfiguration;
import com.astamuse.asta4d.web.WebApplicationContext;
import com.astamuse.asta4d.web.util.SecureIdGenerator;
public class RedirectUtil {
// for performance reason
private static final String KEY_FLASH_SCOPE_ID = WebApplicationConfiguration.getWebApplicationConfiguration()
.getFlashScopeForwardParameterName();
private static final long DATA_EXPIRE_TIME_MILLI_SECONDS = 30_000;
private static final String FlashScopeDataListKey = RedirectUtil.class.getName() + "##FlashScopeDataListKey";
private static final String RedirectInterceptorMapKey = RedirectUtil.class.getName() + "##RedirectInterceptorMapKey";
/**
* <p>
* register a redirect interceptor to current context with duplicated id check, if there has been an interceptor registered by same id,
* the later interceptor will be rejected.
*
* <p>
* <b>NOTE:</b>There is no guaranty about the execution order of registered interceptors.
*
* @param id
* duplication check will be skipped when null specified
* @param interceptor
* @return true: the given interceptor is registered<br>
* false: the given interceptor is no regiestered because the id has been registered
*/
public static final boolean registerRedirectInterceptor(String id, RedirectInterceptor interceptor) {
Context context = Context.getCurrentThreadContext();
Map<String, RedirectInterceptor> map = context.getData(RedirectInterceptorMapKey);
if (map == null) {
map = new HashMap<>();
context.setData(RedirectInterceptorMapKey, map);
}
// we don't do duplicated check for null id
if (id == null) {
map.put(id, interceptor);
return true;
} else {
// we don't do thread lock because we believe all the operations about redirection should be done at the handler side, which
// means there is no concurrent issue.
if (map.get(id) == null) {
map.put(id, interceptor);
return true;
} else {
return false;
}
}
}
public static void addFlashScopeData(Map<String, Object> flashScopeData) {
if (flashScopeData == null || flashScopeData.isEmpty()) {
return;
}
WebApplicationContext context = Context.getCurrentThreadContext();
List<Map<String, Object>> dataList = context.getData(FlashScopeDataListKey);
if (dataList == null) {
dataList = new LinkedList<>();
context.setData(FlashScopeDataListKey, dataList);
}
dataList.add(flashScopeData);
}
public static void addFlashScopeData(String name, Object data) {
Map<String, Object> map = new HashMap<String, Object>();
map.put(name, data);
addFlashScopeData(map);
}
public static void redirectToUrlWithSavedFlashScopeData(HttpServletResponse response, int status, String url) {
// regulate status
if (status == HttpURLConnection.HTTP_MOVED_PERM || status == HttpURLConnection.HTTP_MOVED_TEMP) {
//
} else {
status = HttpURLConnection.HTTP_MOVED_TEMP;
}
// check illegal url
if (url.indexOf('\n') >= 0 || url.indexOf('\r') >= 0) {
throw new RuntimeException("illegal redirct url:" + url);
}
// before redirect task
Map<String, RedirectInterceptor> interceptorMap = Context.getCurrentThreadContext().getData(RedirectInterceptorMapKey);
if (interceptorMap != null) {
for (RedirectInterceptor interceptor : interceptorMap.values()) {
interceptor.beforeRedirect();
}
addFlashScopeData(RedirectInterceptorMapKey, interceptorMap);
}
// create flash data map
Map<String, Object> dataMap = new HashMap<String, Object>();
WebApplicationContext context = Context.getCurrentThreadContext();
List<Map<String, Object>> dataList = context.getData(FlashScopeDataListKey);
if (dataList != null) {
for (Map<String, Object> map : dataList) {
dataMap.putAll(map);
}
}
// save flash data map
if (!dataMap.isEmpty()) {
String flashScopeId = SecureIdGenerator.createEncryptedURLSafeId();
WebApplicationConfiguration.getWebApplicationConfiguration().getExpirableDataManager()
.put(flashScopeId, dataMap, DATA_EXPIRE_TIME_MILLI_SECONDS);
// create target url
if (url.contains("?")) {
url = url + '&' + KEY_FLASH_SCOPE_ID + '=' + flashScopeId;
} else {
url = url + '?' + KEY_FLASH_SCOPE_ID + '=' + flashScopeId;
}
}
// do redirection
response.setStatus(status);
response.addHeader("Location", url);
}
public static void restoreFlashScopeData(HttpServletRequest request) {
String flashScopeId = request.getParameter(RedirectUtil.KEY_FLASH_SCOPE_ID);
if (StringUtils.isEmpty(flashScopeId)) {
return;
} else {
Map<String, Object> savedMap = WebApplicationConfiguration.getWebApplicationConfiguration().getExpirableDataManager()
.get(flashScopeId, true);
if (savedMap == null) {
return;
} else {
WebApplicationContext context = WebApplicationContext.getCurrentThreadWebApplicationContext();
for (Entry<String, Object> entry : savedMap.entrySet()) {
context.setData(WebApplicationContext.SCOPE_FLASH, entry.getKey(), entry.getValue());
}
Map<String, RedirectInterceptor> interceptorMap = context.getData(WebApplicationContext.SCOPE_FLASH,
RedirectInterceptorMapKey);
if (interceptorMap != null) {
for (RedirectInterceptor interceptor : interceptorMap.values()) {
interceptor.afterRedirectDataRestore();
}
}
}
}
}
}