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.portlet.LiferayPortletSession;
026    import com.liferay.portal.kernel.resiliency.spi.agent.annotation.Direction;
027    import com.liferay.portal.kernel.resiliency.spi.agent.annotation.DistributedRegistry;
028    import com.liferay.portal.kernel.servlet.HttpHeaders;
029    import com.liferay.portal.kernel.util.ClassLoaderPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.ThreadLocalDistributor;
032    import com.liferay.portal.kernel.util.ThreadLocalDistributorRegistry;
033    import com.liferay.portal.model.Portlet;
034    import com.liferay.portal.util.ClassLoaderUtil;
035    import com.liferay.portal.util.WebKeys;
036    
037    import java.io.EOFException;
038    import java.io.IOException;
039    import java.io.InputStream;
040    import java.io.OutputStream;
041    import java.io.Serializable;
042    
043    import java.nio.ByteBuffer;
044    
045    import java.util.ArrayList;
046    import java.util.Collections;
047    import java.util.Enumeration;
048    import java.util.HashMap;
049    import java.util.List;
050    import java.util.Map;
051    
052    import javax.servlet.http.HttpServletRequest;
053    import javax.servlet.http.HttpSession;
054    
055    /**
056     * @author Shuyang Zhou
057     */
058    public class SPIAgentSerializable implements Serializable {
059    
060            public static Map<String, Serializable> extractDistributedRequestAttributes(
061                    HttpServletRequest request, Direction direction) {
062    
063                    Map<String, Serializable> distributedRequestAttributes =
064                            new HashMap<String, Serializable>();
065    
066                    Enumeration<String> enumeration = request.getAttributeNames();
067    
068                    while (enumeration.hasMoreElements()) {
069                            String name = enumeration.nextElement();
070    
071                            if (DistributedRegistry.isDistributed(name, direction)) {
072                                    Object value = request.getAttribute(name);
073    
074                                    if (value instanceof Serializable) {
075                                            distributedRequestAttributes.put(name, (Serializable)value);
076                                    }
077                                    else if (_log.isWarnEnabled()) {
078                                            _log.warn(
079                                                    "Nonserializable distributed request attribute name " +
080                                                            name + " with value " + value);
081                                    }
082                            }
083                            else if (_log.isDebugEnabled()) {
084                                    _log.debug(
085                                            "Nondistributed request attribute name " + name +
086                                                    " with direction " + direction + " and value " +
087                                                            request.getAttribute(name));
088                            }
089                    }
090    
091                    return distributedRequestAttributes;
092            }
093    
094            public static Map<String, List<String>> extractRequestHeaders(
095                    HttpServletRequest request) {
096    
097                    Map<String, List<String>> headers = new HashMap<String, List<String>>();
098    
099                    Enumeration<String> nameEnumeration = request.getHeaderNames();
100    
101                    while (nameEnumeration.hasMoreElements()) {
102                            String headerName = nameEnumeration.nextElement();
103    
104                            // Remove Accept-Encoding header, to prevent content modification
105    
106                            if (StringUtil.equalsIgnoreCase(
107                                            HttpHeaders.ACCEPT_ENCODING, headerName)) {
108    
109                                    continue;
110                            }
111    
112                            // Directly passing around cookie
113    
114                            if (StringUtil.equalsIgnoreCase(HttpHeaders.COOKIE, headerName)) {
115                                    continue;
116                            }
117    
118                            Enumeration<String> valueEnumeration = request.getHeaders(
119                                    headerName);
120    
121                            if (valueEnumeration != null) {
122                                    List<String> values = new ArrayList<String>();
123    
124                                    while (valueEnumeration.hasMoreElements()) {
125                                            values.add(valueEnumeration.nextElement());
126                                    }
127    
128                                    if (values.isEmpty()) {
129                                            values = Collections.emptyList();
130                                    }
131    
132                                    headers.put(StringUtil.toLowerCase(headerName), values);
133                            }
134                    }
135    
136                    if (headers.isEmpty()) {
137                            headers = Collections.emptyMap();
138                    }
139    
140                    return headers;
141            }
142    
143            public static Map<String, Serializable> extractSessionAttributes(
144                    HttpServletRequest request) {
145    
146                    HttpSession session = request.getSession();
147    
148                    Portlet portlet = (Portlet)request.getAttribute(
149                            WebKeys.SPI_AGENT_PORTLET);
150    
151                    String namespace = LiferayPortletSession.PORTLET_SCOPE_NAMESPACE.concat(
152                            portlet.getPortletId()).concat(
153                                    LiferayPortletSession.LAYOUT_SEPARATOR);
154    
155                    Map<String, Serializable> sessionAttributes =
156                            new HashMap<String, Serializable>();
157    
158                    Enumeration<String> enumeration = session.getAttributeNames();
159    
160                    while (enumeration.hasMoreElements()) {
161                            String name = enumeration.nextElement();
162    
163                            if (name.startsWith(
164                                            LiferayPortletSession.PORTLET_SCOPE_NAMESPACE) &&
165                                    !name.startsWith(namespace)) {
166    
167                                    continue;
168                            }
169    
170                            Object value = session.getAttribute(name);
171    
172                            if (value instanceof Serializable) {
173                                    sessionAttributes.put(name, (Serializable)value);
174                            }
175                            else if (_log.isWarnEnabled()) {
176                                    _log.warn(
177                                            "Nonserializable session attribute name " + name +
178                                                    " with value " + value);
179                            }
180                    }
181    
182                    return sessionAttributes;
183            }
184    
185            public static <T extends SPIAgentSerializable> T readFrom(
186                            InputStream inputStream)
187                    throws IOException {
188    
189                    byte[] data = new byte[8];
190                    int length = 0;
191    
192                    while (length < 8) {
193                            int count = inputStream.read(data, length, 8 - length);
194    
195                            if (count < 0) {
196                                    throw new EOFException();
197                            }
198    
199                            length += count;
200                    }
201    
202                    long receipt = BigEndianCodec.getLong(data, 0);
203    
204                    ByteBuffer byteBuffer = MailboxUtil.receiveMail(receipt);
205    
206                    if (byteBuffer == null) {
207                            throw new IllegalArgumentException(
208                                    "No mail with receipt " + receipt);
209                    }
210    
211                    Deserializer deserializer = new Deserializer(byteBuffer);
212    
213                    ClassLoader contextClassLoader =
214                            ClassLoaderUtil.getContextClassLoader();
215    
216                    try {
217                            String servletContextName = deserializer.readString();
218    
219                            ClassLoader classLoader = ClassLoaderPool.getClassLoader(
220                                    servletContextName);
221    
222                            ClassLoaderUtil.setContextClassLoader(classLoader);
223    
224                            return deserializer.readObject();
225                    }
226                    catch (ClassNotFoundException cnfe) {
227                            throw new IOException(cnfe);
228                    }
229                    finally {
230                            ClassLoaderUtil.setContextClassLoader(contextClassLoader);
231                    }
232            }
233    
234            public SPIAgentSerializable(String servletContextName) {
235                    this.servletContextName = servletContextName;
236            }
237    
238            public void writeTo(
239                            RegistrationReference registrationReference,
240                            OutputStream outputStream)
241                    throws IOException {
242    
243                    Serializer serializer = new Serializer();
244    
245                    serializer.writeString(servletContextName);
246                    serializer.writeObject(this);
247    
248                    try {
249                            byte[] data = new byte[8];
250    
251                            ByteBuffer byteBuffer = serializer.toByteBuffer();
252    
253                            long receipt = MailboxUtil.sendMail(
254                                    registrationReference, byteBuffer);
255    
256                            BigEndianCodec.putLong(data, 0, receipt);
257    
258                            outputStream.write(data);
259    
260                            outputStream.flush();
261                    }
262                    catch (MailboxException me) {
263                            throw new IOException(me);
264                    }
265            }
266    
267            protected void captureThreadLocals() {
268                    threadLocalDistributors =
269                            ThreadLocalDistributorRegistry.getThreadLocalDistributors();
270    
271                    for (ThreadLocalDistributor threadLocalDistributor :
272                                    threadLocalDistributors) {
273    
274                            threadLocalDistributor.capture();
275                    }
276            }
277    
278            protected void restoreThreadLocals() {
279                    for (ThreadLocalDistributor threadLocalDistributor :
280                                    threadLocalDistributors) {
281    
282                            threadLocalDistributor.restore();
283                    }
284            }
285    
286            protected transient final String servletContextName;
287            protected ThreadLocalDistributor[] threadLocalDistributors;
288    
289            private static Log _log = LogFactoryUtil.getLog(SPIAgentSerializable.class);
290    
291    }