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