/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.resiliency.spi.agent;
import com.liferay.portal.kernel.io.BigEndianCodec;
import com.liferay.portal.kernel.io.Deserializer;
import com.liferay.portal.kernel.io.Serializer;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Portlet;
import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
import com.liferay.portal.kernel.nio.intraband.mailbox.MailboxException;
import com.liferay.portal.kernel.nio.intraband.mailbox.MailboxUtil;
import com.liferay.portal.kernel.resiliency.spi.agent.annotation.Direction;
import com.liferay.portal.kernel.resiliency.spi.agent.annotation.DistributedRegistry;
import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.util.ClassLoaderPool;
import com.liferay.portal.kernel.util.ClassLoaderUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.ThreadLocalDistributor;
import com.liferay.portal.kernel.util.ThreadLocalDistributorRegistry;
import com.liferay.portal.kernel.util.WebKeys;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @author Shuyang Zhou
*/
public class SPIAgentSerializable implements Serializable {
public static Map<String, Serializable> extractDistributedRequestAttributes(
HttpServletRequest request, Direction direction) {
Map<String, Serializable> distributedRequestAttributes =
new HashMap<>();
Enumeration<String> enumeration = request.getAttributeNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
if (DistributedRegistry.isDistributed(name, direction)) {
Object value = request.getAttribute(name);
if (value instanceof Serializable) {
distributedRequestAttributes.put(name, (Serializable)value);
}
else if (_log.isWarnEnabled()) {
_log.warn(
"Nonserializable distributed request attribute name " +
name + " with value " + value);
}
}
else if (_log.isDebugEnabled()) {
_log.debug(
"Nondistributed request attribute name " + name +
" with direction " + direction + " and value " +
request.getAttribute(name));
}
}
return distributedRequestAttributes;
}
public static Map<String, List<String>> extractRequestHeaders(
HttpServletRequest request) {
Map<String, List<String>> headers = new HashMap<>();
Enumeration<String> nameEnumeration = request.getHeaderNames();
while (nameEnumeration.hasMoreElements()) {
String headerName = nameEnumeration.nextElement();
// Remove Accept-Encoding header, to prevent content modification
if (StringUtil.equalsIgnoreCase(
HttpHeaders.ACCEPT_ENCODING, headerName)) {
continue;
}
// Directly passing around cookie
if (StringUtil.equalsIgnoreCase(HttpHeaders.COOKIE, headerName)) {
continue;
}
Enumeration<String> valueEnumeration = request.getHeaders(
headerName);
if (valueEnumeration != null) {
List<String> values = new ArrayList<>();
while (valueEnumeration.hasMoreElements()) {
values.add(valueEnumeration.nextElement());
}
if (values.isEmpty()) {
values = Collections.emptyList();
}
headers.put(StringUtil.toLowerCase(headerName), values);
}
}
if (headers.isEmpty()) {
headers = Collections.emptyMap();
}
return headers;
}
public static Map<String, Serializable> extractSessionAttributes(
HttpServletRequest request) {
Portlet portlet = (Portlet)request.getAttribute(
WebKeys.SPI_AGENT_PORTLET);
String portletSessionAttributesKey =
WebKeys.PORTLET_SESSION_ATTRIBUTES.concat(portlet.getContextName());
Map<String, Serializable> sessionAttributes = new HashMap<>();
HttpSession session = request.getSession();
Enumeration<String> enumeration = session.getAttributeNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
if (name.startsWith(WebKeys.PORTLET_SESSION_ATTRIBUTES) &&
!name.equals(portletSessionAttributesKey)) {
continue;
}
Object value = session.getAttribute(name);
if (value instanceof Serializable) {
sessionAttributes.put(name, (Serializable)value);
}
else if (_log.isWarnEnabled()) {
_log.warn(
"Nonserializable session attribute name " + name +
" with value " + value);
}
}
HttpSession portletSession = (HttpSession)request.getAttribute(
WebKeys.PORTLET_SESSION);
if (portletSession != null) {
request.removeAttribute(WebKeys.PORTLET_SESSION);
HashMap<String, Serializable> portletSessionAttributes =
new HashMap<>();
enumeration = portletSession.getAttributeNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
Object value = portletSession.getAttribute(name);
if (value instanceof Serializable) {
portletSessionAttributes.put(name, (Serializable)value);
}
else if (_log.isWarnEnabled()) {
_log.warn(
"Nonserializable session attribute name " + name +
" with value " + value);
}
}
sessionAttributes.put(
portletSessionAttributesKey, portletSessionAttributes);
}
return sessionAttributes;
}
public static <T extends SPIAgentSerializable> T readFrom(
InputStream inputStream)
throws IOException {
byte[] data = new byte[8];
int length = 0;
while (length < 8) {
int count = inputStream.read(data, length, 8 - length);
if (count < 0) {
throw new EOFException();
}
length += count;
}
long receipt = BigEndianCodec.getLong(data, 0);
ByteBuffer byteBuffer = MailboxUtil.receiveMail(receipt);
if (byteBuffer == null) {
throw new IllegalArgumentException(
"No mail with receipt " + receipt);
}
Deserializer deserializer = new Deserializer(byteBuffer);
ClassLoader contextClassLoader =
ClassLoaderUtil.getContextClassLoader();
try {
String servletContextName = deserializer.readString();
ClassLoader classLoader = ClassLoaderPool.getClassLoader(
servletContextName);
ClassLoaderUtil.setContextClassLoader(classLoader);
T t = deserializer.readObject();
t.servletContextName = servletContextName;
return t;
}
catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
finally {
ClassLoaderUtil.setContextClassLoader(contextClassLoader);
}
}
public SPIAgentSerializable(String servletContextName) {
this.servletContextName = servletContextName;
}
public void writeTo(
RegistrationReference registrationReference,
OutputStream outputStream)
throws IOException {
Serializer serializer = new Serializer();
serializer.writeString(servletContextName);
serializer.writeObject(this);
try {
byte[] data = new byte[8];
ByteBuffer byteBuffer = serializer.toByteBuffer();
long receipt = MailboxUtil.sendMail(
registrationReference, byteBuffer);
BigEndianCodec.putLong(data, 0, receipt);
outputStream.write(data);
outputStream.flush();
}
catch (MailboxException me) {
throw new IOException(me);
}
}
protected void captureThreadLocals() {
threadLocalDistributors =
ThreadLocalDistributorRegistry.getThreadLocalDistributors();
for (ThreadLocalDistributor threadLocalDistributor :
threadLocalDistributors) {
threadLocalDistributor.capture();
}
}
protected void restoreThreadLocals() {
for (ThreadLocalDistributor threadLocalDistributor :
threadLocalDistributors) {
threadLocalDistributor.restore();
}
}
protected transient String servletContextName;
protected ThreadLocalDistributor[] threadLocalDistributors;
private static final Log _log = LogFactoryUtil.getLog(
SPIAgentSerializable.class);
}