001    /**
002     * Copyright (c) 2000-2012 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.kernel.servlet.liferaypackage;
016    
017    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
018    import com.liferay.portal.kernel.cluster.ClusterNode;
019    import com.liferay.portal.kernel.cluster.ClusterNodeResponse;
020    import com.liferay.portal.kernel.cluster.ClusterNodeResponses;
021    import com.liferay.portal.kernel.cluster.ClusterRequest;
022    import com.liferay.portal.kernel.cluster.FutureClusterResponses;
023    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
024    import com.liferay.portal.kernel.deploy.hot.LiferayPackageHotDeployException;
025    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
026    import com.liferay.portal.kernel.servlet.ServletContextPool;
027    import com.liferay.portal.kernel.servlet.filters.LiferayPackageFilter;
028    import com.liferay.portal.kernel.servlet.filters.invoker.FilterMapping;
029    import com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterConfig;
030    import com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterHelper;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.portal.kernel.util.MethodHandler;
033    import com.liferay.portal.kernel.util.MethodKey;
034    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
035    import com.liferay.portal.kernel.util.StreamUtil;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.Validator;
038    import com.liferay.portal.kernel.workflow.WorkflowConstants;
039    import com.liferay.portal.license.util.LicenseManagerUtil;
040    
041    import java.io.InputStream;
042    
043    import java.lang.reflect.Constructor;
044    import java.lang.reflect.Method;
045    
046    import java.sql.Connection;
047    import java.sql.PreparedStatement;
048    import java.sql.ResultSet;
049    
050    import java.util.ArrayList;
051    import java.util.HashMap;
052    import java.util.List;
053    import java.util.Map;
054    import java.util.concurrent.TimeUnit;
055    
056    import javax.servlet.Filter;
057    import javax.servlet.FilterConfig;
058    import javax.servlet.ServletContext;
059    
060    /**
061     * @author Amos Fong
062     */
063    public class LiferayPackageUtil {
064    
065            public static void checkPackage() throws Exception {
066                    if (_getProductType() == _productTypeEE) {
067                            int licenseState = LicenseManagerUtil.getLicenseState(
068                                    _productIdPortal);
069    
070                            if (licenseState != _stateGood) {
071                                    LicenseManagerUtil.checkLicense(_productIdPortal);
072    
073                                    licenseState = LicenseManagerUtil.getLicenseState(
074                                            _productIdPortal);
075                            }
076    
077                            if (licenseState != _stateGood) {
078                                    throw new LiferayPackageHotDeployException(
079                                            "This application requires a valid Liferay Portal EE " +
080                                                    "license.");
081                            }
082                    }
083    
084                    if (Validator.isNull(_getProductId())) {
085                            return;
086                    }
087    
088                    int licenseState = _getLicenseState(
089                            _getProductId(), _getProductVersion());
090    
091                    if (licenseState != _stateGood) {
092                            LicenseManagerUtil.checkLicense(_getProductId());
093    
094                            licenseState = _getLicenseState(
095                                    _getProductId(), _getProductVersion());
096                    }
097    
098                    if (licenseState != _stateGood) {
099                            throw new LiferayPackageHotDeployException(
100                                    "This application does not have a valid license");
101                    }
102    
103                    Map<String, String> licenseProperties =
104                            LicenseManagerUtil.getLicenseProperties(_getProductId());
105    
106                    if (licenseProperties == null) {
107                            throw new LiferayPackageHotDeployException(
108                                    "This Liferay version does not support this application.");
109                    }
110    
111                    if (licenseProperties != null) {
112                            int maxValidProductVersion = GetterUtil.getInteger(
113                                    licenseProperties.get("productVersion"));
114    
115                            if ((_getProductVersion() > 0) &&
116                                    (_getProductVersion() > maxValidProductVersion)) {
117    
118                                    throw new LiferayPackageHotDeployException(
119                                            "The version of your application is not compatible with " +
120                                                    "the registered license");
121                            }
122                    }
123    
124                    List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();
125    
126                    if (clusterNodes.size() <= 1) {
127                            return;
128                    }
129    
130                    clusterNodes.remove(ClusterExecutorUtil.getLocalClusterNode());
131    
132                    for (ClusterNode clusterNode : clusterNodes) {
133                            MethodHandler methodHandler = new MethodHandler(
134                                    _getLicenseStateMethodKey, _getProductId());
135    
136                            ClusterRequest clusterRequest = ClusterRequest.createUnicastRequest(
137                                    methodHandler, clusterNode.getClusterNodeId());
138    
139                            FutureClusterResponses futureClusterResponses =
140                                    ClusterExecutorUtil.execute(clusterRequest);
141    
142                            ClusterNodeResponses clusterNodeResponses =
143                                    futureClusterResponses.get(10000, TimeUnit.MILLISECONDS);
144    
145                            ClusterNodeResponse clusterNodeResponse =
146                                    clusterNodeResponses.getClusterResponse(clusterNode);
147    
148                            Object result = clusterNodeResponse.getResult();
149    
150                            if (result == null) {
151                                    return;
152                            }
153    
154                            Integer remoteLicenseState = (Integer)result;
155    
156                            if (remoteLicenseState != _stateGood) {
157                                    throw new LiferayPackageHotDeployException(
158                                            "A clustered server has an invalid license.");
159                            }
160                    }
161            }
162    
163            public static void registerFilter(
164                            ServletContext servletContext, String pathContext)
165                    throws LiferayPackageHotDeployException {
166    
167                    _pathContext = pathContext;
168    
169                    Map<String, String> licenseProperties =
170                            LicenseManagerUtil.getLicenseProperties(_getProductId());
171    
172                    String description = GetterUtil.getString(
173                            licenseProperties.get("description"));
174    
175                    if (!description.startsWith("Developer License")) {
176                            return;
177                    }
178    
179                    try {
180                            InvokerFilterHelper invokerFilterHelper = _getInvokerFilterHelper(
181                                    pathContext);
182    
183                            Filter liferayPackageFilter = _getFilter(
184                                    servletContext.getServletContextName(),
185                                    pathContext + "/c/portal/license");
186    
187                            FilterConfig filterConfig = new InvokerFilterConfig(
188                                    servletContext, _getFilterName(),
189                                    new HashMap<String, String>());
190    
191                            liferayPackageFilter.init(filterConfig);
192    
193                            invokerFilterHelper.registerFilter(
194                                    _getFilterName(), liferayPackageFilter);
195    
196                            List<String> urlPatterns = new ArrayList<String>();
197    
198                            urlPatterns.add("/*");
199    
200                            _filterMapping = new FilterMapping(
201                                    liferayPackageFilter, filterConfig, urlPatterns,
202                                    new ArrayList<String>());
203    
204                            invokerFilterHelper.registerFilterMapping(
205                                    _filterMapping, null, false);
206                    }
207                    catch (Exception e) {
208                            throw new LiferayPackageHotDeployException(
209                                    "Unable to intialize Liferay package filter");
210                    }
211            }
212    
213            public static void unregisterFilter() {
214                    if (_pathContext == null) {
215                            return;
216                    }
217    
218                    InvokerFilterHelper invokerFilterHelper = _getInvokerFilterHelper(
219                            _pathContext);
220    
221                    if (invokerFilterHelper == null) {
222                            return;
223                    }
224    
225                    Filter filter = invokerFilterHelper.registerFilter(
226                            _getFilterName(), null);
227    
228                    if (filter != null) {
229                            filter.destroy();
230                    }
231    
232                    if (_filterMapping != null) {
233                            invokerFilterHelper.unregisterFilterMapping(_filterMapping);
234                    }
235            }
236    
237            private static Filter _getFilter(
238                            String servletContextName, String licensePageURL)
239                    throws Exception {
240    
241                    ClassLoader classLoader = LiferayPackageUtil.class.getClassLoader();
242    
243                    String className = LiferayPackageFilter.class.getName();
244    
245                    InputStream inputStream = classLoader.getResourceAsStream(
246                            className.replace(StringPool.PERIOD, StringPool.SLASH) + ".class");
247    
248                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
249                            new UnsyncByteArrayOutputStream();
250    
251                    StreamUtil.transfer(inputStream, unsyncByteArrayOutputStream, true);
252    
253                    byte[] bytes = unsyncByteArrayOutputStream.toByteArray();
254    
255                    ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
256    
257                    Method defineClassMethod = ClassLoader.class.getDeclaredMethod(
258                            "defineClass", String.class, byte[].class, int.class, int.class);
259    
260                    defineClassMethod.setAccessible(true);
261    
262                    Class<?> liferayPackageFilterClass = (Class<?>)defineClassMethod.invoke(
263                            portalClassLoader, LiferayPackageFilter.class.getName(), bytes, 0,
264                            bytes.length);
265    
266                    Constructor<?> liferayPackageFilterConstructor =
267                            liferayPackageFilterClass.getConstructor(
268                                    String.class, String.class);
269    
270                    return (Filter)liferayPackageFilterConstructor.newInstance(
271                            servletContextName, licensePageURL);
272            }
273    
274            private static String _getFilterName() {
275                    return "Liferay Package Filter - " + _getProductId();
276            }
277    
278            private static InvokerFilterHelper _getInvokerFilterHelper(
279                    String pathContext) {
280    
281                    ServletContext portalServletContext = ServletContextPool.get(
282                            pathContext);
283    
284                    if (portalServletContext == null) {
285                            return null;
286                    }
287    
288                    InvokerFilterHelper invokerFilterHelper =
289                            (InvokerFilterHelper)portalServletContext.getAttribute(
290                                    InvokerFilterHelper.class.getName());
291    
292                    return invokerFilterHelper;
293            }
294    
295            private static int _getLicenseState(String productId, int productVersion)
296                    throws Exception {
297    
298                    Map<String, String> licenseProperties = new HashMap<String, String>();
299    
300                    licenseProperties.put("productId", productId);
301                    licenseProperties.put("productVersion", String.valueOf(productVersion));
302                    licenseProperties.put("userCount", String.valueOf(_getUserCount()));
303    
304                    return LicenseManagerUtil.getLicenseState(licenseProperties);
305            }
306    
307            private static String _getProductId() {
308                    return _productId;
309            }
310    
311            private static int _getProductType() {
312                    return GetterUtil.getInteger(_productType);
313            }
314    
315            private static int _getProductVersion() {
316                    return GetterUtil.getInteger(_productVersion);
317            }
318    
319            private static long _getUserCount() throws Exception {
320                    Connection con = null;
321                    PreparedStatement ps = null;
322                    ResultSet rs = null;
323    
324                    try {
325                            con = DataAccess.getConnection();
326    
327                            ps = con.prepareStatement(
328                                    "select count(*) from User_ where (defaultUser = ?) and " +
329                                            "(status = ?)");
330    
331                            ps.setBoolean(1, false);
332                            ps.setLong(2, WorkflowConstants.STATUS_APPROVED);
333    
334                            rs = ps.executeQuery();
335    
336                            while (rs.next()) {
337                                    long count = rs.getLong(1);
338    
339                                    if (count > 0) {
340                                            return count;
341                                    }
342                            }
343                    }
344                    finally {
345                            DataAccess.cleanUp(con, ps, rs);
346                    }
347    
348                    throw new Exception("Unable to count number of users on server");
349            }
350    
351            private static final String _productId = "_PRODUCT_ID_";
352            private static final String _productIdPortal = "Portal";
353            private static final String _productType = "_PRODUCT_TYPE_";
354            private static final int _productTypeEE = 2;
355            private static final String _productVersion = "_PRODUCT_VERSION_";
356            private static final int _stateGood = 3;
357    
358            private static FilterMapping _filterMapping;
359            private static MethodKey _getLicenseStateMethodKey = new MethodKey(
360                    LicenseManagerUtil.class, "getLicenseState", String.class);
361            private static String _pathContext;
362    
363    }