001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.resiliency.spi.agent;
016    
017    import com.liferay.portal.kernel.io.BigEndianCodec;
018    import com.liferay.portal.kernel.io.Deserializer;
019    import com.liferay.portal.kernel.io.Serializer;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
023    import com.liferay.portal.kernel.nio.intraband.mailbox.MailboxException;
024    import com.liferay.portal.kernel.nio.intraband.mailbox.MailboxUtil;
025    import com.liferay.portal.kernel.resiliency.spi.agent.annotation.Direction;
026    import com.liferay.portal.kernel.resiliency.spi.agent.annotation.DistributedRegistry;
027    import com.liferay.portal.kernel.servlet.HttpHeaders;
028    import com.liferay.portal.kernel.util.ClassLoaderPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.ThreadLocalDistributor;
031    import com.liferay.portal.kernel.util.ThreadLocalDistributorRegistry;
032    import com.liferay.portal.model.Portlet;
033    import com.liferay.portal.util.ClassLoaderUtil;
034    import com.liferay.portal.util.WebKeys;
035    
036    import java.io.EOFException;
037    import java.io.IOException;
038    import java.io.InputStream;
039    import java.io.OutputStream;
040    import java.io.Serializable;
041    
042    import java.nio.ByteBuffer;
043    
044    import java.util.ArrayList;
045    import java.util.Collections;
046    import java.util.Enumeration;
047    import java.util.HashMap;
048    import java.util.List;
049    import java.util.Map;
050    
051    import javax.servlet.http.HttpServletRequest;
052    import javax.servlet.http.HttpSession;
053    
054    /**
055     * @author Shuyang Zhou
056     */
057    public class SPIAgentSerializable implements Serializable {
058    
059            public static Map<String, Serializable> extractDistributedRequestAttributes(
060                    HttpServletRequest request, Direction direction) {
061    
062                    Map<String, Serializable> distributedRequestAttributes =
063                            new HashMap<String, Serializable>();
064    
065                    Enumeration<String> enumeration = request.getAttributeNames();
066    
067                    while (enumeration.hasMoreElements()) {
068                            String name = enumeration.nextElement();
069    
070                            if (DistributedRegistry.isDistributed(name, direction)) {
071                                    Object value = request.getAttribute(name);
072    
073                                    if (value instanceof Serializable) {
074                                            distributedRequestAttributes.put(name, (Serializable)value);
075                                    }
076                                    else if (_log.isWarnEnabled()) {
077                                            _log.warn(
078                                                    "Nonserializable distributed request attribute name " +
079                                                            name + " with value " + value);
080                                    }
081                            }
082                            else if (_log.isDebugEnabled()) {
083                                    _log.debug(
084                                            "Nondistributed request attribute name " + name +
085                                                    " with direction " + direction + " and value " +
086                                                            request.getAttribute(name));
087                            }
088                    }
089    
090                    return distributedRequestAttributes;
091            }
092    
093            public static Map<String, List<String>> extractRequestHeaders(
094                    HttpServletRequest request) {
095    
096                    Map<String, List<String>> headers = new HashMap<String, List<String>>();
097    
098                    Enumeration<String> nameEnumeration = request.getHeaderNames();
099    
100                    while (nameEnumeration.hasMoreElements()) {
101                            String headerName = nameEnumeration.nextElement();
102    
103                            // Remove Accept-Encoding header, to prevent content modification
104    
105                            if (StringUtil.equalsIgnoreCase(
106                                            HttpHeaders.ACCEPT_ENCODING, headerName)) {
107    
108                                    continue;
109                            }
110    
111                            // Directly passing around cookie
112    
113                            if (StringUtil.equalsIgnoreCase(HttpHeaders.COOKIE, headerName)) {
114                                    continue;
115                            }
116    
117                            Enumeration<String> valueEnumeration = request.getHeaders(
118                                    headerName);
119    
120                            if (valueEnumeration != null) {
121                                    List<String> values = new ArrayList<String>();
122    
123                                    while (valueEnumeration.hasMoreElements()) {
124                                            values.add(valueEnumeration.nextElement());
125                                    }
126    
127                                    if (values.isEmpty()) {
128                                            values = Collections.emptyList();
129                                    }
130    
131                                    headers.put(StringUtil.toLowerCase(headerName), values);
132                            }
133                    }
134    
135                    if (headers.isEmpty()) {
136                            headers = Collections.emptyMap();
137                    }
138    
139                    return headers;
140            }
141    
142            public static Map<String, Serializable> extractSessionAttributes(
143                    HttpServletRequest request) {
144    
145                    Portlet portlet = (Portlet)request.getAttribute(
146                            WebKeys.SPI_AGENT_PORTLET);
147    
148                    String portletSessionAttributesKey =
149                            WebKeys.PORTLET_SESSION_ATTRIBUTES.concat(portlet.getContextName());
150    
151                    Map<String, Serializable> sessionAttributes =
152                            new HashMap<String, Serializable>();
153    
154                    HttpSession session = request.getSession();
155    
156                    Enumeration<String> enumeration = session.getAttributeNames();
157    
158                    while (enumeration.hasMoreElements()) {
159                            String name = enumeration.nextElement();
160    
161                            if (name.startsWith(WebKeys.PORTLET_SESSION_ATTRIBUTES) &&
162                                    !name.equals(portletSessionAttributesKey)) {
163    
164                                    continue;
165                            }
166    
167                            Object value = session.getAttribute(name);
168    
169                            if (value instanceof Serializable) {
170                                    sessionAttributes.put(name, (Serializable)value);
171                            }
172                            else if (_log.isWarnEnabled()) {
173                                    _log.warn(
174                                            "Nonserializable session attribute name " + name +
175                                                    " with value " + value);
176                            }
177                    }
178    
179                    HttpSession portletSession = (HttpSession)request.getAttribute(
180                            WebKeys.PORTLET_SESSION);
181    
182                    if (portletSession != null) {
183                            request.removeAttribute(WebKeys.PORTLET_SESSION);
184    
185                            HashMap<String, Serializable> portletSessionAttributes =
186                                    new HashMap<String, Serializable>();
187    
188                            enumeration = portletSession.getAttributeNames();
189    
190                            while (enumeration.hasMoreElements()) {
191                                    String name = enumeration.nextElement();
192                                    Object value = portletSession.getAttribute(name);
193    
194                                    if (value instanceof Serializable) {
195                                            portletSessionAttributes.put(name, (Serializable)value);
196                                    }
197                                    else if (_log.isWarnEnabled()) {
198                                            _log.warn(
199                                                    "Nonserializable session attribute name " + name +
200                                                            " with value " + value);
201                                    }
202                            }
203    
204                            sessionAttributes.put(
205                                    portletSessionAttributesKey, portletSessionAttributes);
206                    }
207    
208                    return sessionAttributes;
209            }
210    
211            public static <T extends SPIAgentSerializable> T readFrom(
212                            InputStream inputStream)
213                    throws IOException {
214    
215                    byte[] data = new byte[8];
216                    int length = 0;
217    
218                    while (length < 8) {
219                            int count = inputStream.read(data, length, 8 - length);
220    
221                            if (count < 0) {
222                                    throw new EOFException();
223                            }
224    
225                            length += count;
226                    }
227    
228                    long receipt = BigEndianCodec.getLong(data, 0);
229    
230                    ByteBuffer byteBuffer = MailboxUtil.receiveMail(receipt);
231    
232                    if (byteBuffer == null) {
233                            throw new IllegalArgumentException(
234                                    "No mail with receipt " + receipt);
235                    }
236    
237                    Deserializer deserializer = new Deserializer(byteBuffer);
238    
239                    ClassLoader contextClassLoader =
240                            ClassLoaderUtil.getContextClassLoader();
241    
242                    try {
243                            String servletContextName = deserializer.readString();
244    
245                            ClassLoader classLoader = ClassLoaderPool.getClassLoader(
246                                    servletContextName);
247    
248                            ClassLoaderUtil.setContextClassLoader(classLoader);
249    
250                            T t = deserializer.readObject();
251    
252                            t.servletContextName = servletContextName;
253    
254                            return t;
255                    }
256                    catch (ClassNotFoundException cnfe) {
257                            throw new IOException(cnfe);
258                    }
259                    finally {
260                            ClassLoaderUtil.setContextClassLoader(contextClassLoader);
261                    }
262            }
263    
264            public SPIAgentSerializable(String servletContextName) {
265                    this.servletContextName = servletContextName;
266            }
267    
268            public void writeTo(
269                            RegistrationReference registrationReference,
270                            OutputStream outputStream)
271                    throws IOException {
272    
273                    Serializer serializer = new Serializer();
274    
275                    serializer.writeString(servletContextName);
276                    serializer.writeObject(this);
277    
278                    try {
279                            byte[] data = new byte[8];
280    
281                            ByteBuffer byteBuffer = serializer.toByteBuffer();
282    
283                            long receipt = MailboxUtil.sendMail(
284                                    registrationReference, byteBuffer);
285    
286                            BigEndianCodec.putLong(data, 0, receipt);
287    
288                            outputStream.write(data);
289    
290                            outputStream.flush();
291                    }
292                    catch (MailboxException me) {
293                            throw new IOException(me);
294                    }
295            }
296    
297            protected void captureThreadLocals() {
298                    threadLocalDistributors =
299                            ThreadLocalDistributorRegistry.getThreadLocalDistributors();
300    
301                    for (ThreadLocalDistributor threadLocalDistributor :
302                                    threadLocalDistributors) {
303    
304                            threadLocalDistributor.capture();
305                    }
306            }
307    
308            protected void restoreThreadLocals() {
309                    for (ThreadLocalDistributor threadLocalDistributor :
310                                    threadLocalDistributors) {
311    
312                            threadLocalDistributor.restore();
313                    }
314            }
315    
316            protected transient String servletContextName;
317            protected ThreadLocalDistributor[] threadLocalDistributors;
318    
319            private static Log _log = LogFactoryUtil.getLog(SPIAgentSerializable.class);
320    
321    }