001    /**
002     * Copyright (c) 2000-present 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.tools;
016    
017    import com.liferay.portal.dao.orm.common.SQLTransformer;
018    import com.liferay.portal.events.StartupHelperUtil;
019    import com.liferay.portal.kernel.cache.CacheRegistryUtil;
020    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
021    import com.liferay.portal.kernel.dao.db.DB;
022    import com.liferay.portal.kernel.dao.db.DBManagerUtil;
023    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
024    import com.liferay.portal.kernel.log.Log;
025    import com.liferay.portal.kernel.log.LogFactoryUtil;
026    import com.liferay.portal.kernel.module.framework.ModuleServiceLifecycle;
027    import com.liferay.portal.kernel.util.ReleaseInfo;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.Time;
030    import com.liferay.portal.model.Release;
031    import com.liferay.portal.model.ReleaseConstants;
032    import com.liferay.portal.service.ClassNameLocalServiceUtil;
033    import com.liferay.portal.service.ReleaseLocalServiceUtil;
034    import com.liferay.portal.service.ResourceActionLocalServiceUtil;
035    import com.liferay.portal.transaction.TransactionsUtil;
036    import com.liferay.portal.util.InitUtil;
037    import com.liferay.portal.util.PropsValues;
038    import com.liferay.registry.Registry;
039    import com.liferay.registry.RegistryUtil;
040    import com.liferay.registry.ServiceRegistrar;
041    import com.liferay.util.dao.orm.CustomSQLUtil;
042    
043    import java.sql.Connection;
044    import java.sql.Date;
045    import java.sql.PreparedStatement;
046    import java.sql.ResultSet;
047    
048    import java.util.HashMap;
049    import java.util.Map;
050    
051    import org.apache.commons.lang.time.StopWatch;
052    
053    /**
054     * @author Michael C. Han
055     * @author Brian Wing Shun Chan
056     */
057    public class DBUpgrader {
058    
059            public static void main(String[] args) {
060                    try {
061                            StopWatch stopWatch = new StopWatch();
062    
063                            stopWatch.start();
064    
065                            InitUtil.initWithSpring(true);
066    
067                            upgrade();
068                            verify();
069    
070                            Registry registry = RegistryUtil.getRegistry();
071    
072                            Map<String, Object> properties = new HashMap<>();
073    
074                            properties.put("module.service.lifecycle", "portal.initialized");
075                            properties.put("service.vendor", ReleaseInfo.getVendor());
076                            properties.put("service.version", ReleaseInfo.getVersion());
077    
078                            registry.registerService(
079                                    ModuleServiceLifecycle.class, new ModuleServiceLifecycle() {},
080                                    properties);
081    
082                            System.out.println(
083                                    "\nCompleted Liferay core upgrade and verify processes in " +
084                                            (stopWatch.getTime() / Time.SECOND) + " seconds");
085    
086                            System.out.println(
087                                    "Running modules upgrades. Connect to your Gogo Shell to " +
088                                            "check the status.");
089                    }
090                    catch (Exception e) {
091                            e.printStackTrace();
092    
093                            System.exit(1);
094                    }
095            }
096    
097            public static void upgrade() throws Exception {
098    
099                    // Disable database caching before upgrade
100    
101                    if (_log.isDebugEnabled()) {
102                            _log.debug("Disable cache registry");
103                    }
104    
105                    CacheRegistryUtil.setActive(false);
106    
107                    // Check release
108    
109                    int buildNumber = ReleaseLocalServiceUtil.getBuildNumberOrCreate();
110    
111                    if (buildNumber > ReleaseInfo.getParentBuildNumber()) {
112                            StringBundler sb = new StringBundler(6);
113    
114                            sb.append("Attempting to deploy an older Liferay Portal version. ");
115                            sb.append("Current build version is ");
116                            sb.append(buildNumber);
117                            sb.append(" and attempting to deploy version ");
118                            sb.append(ReleaseInfo.getParentBuildNumber());
119                            sb.append(".");
120    
121                            throw new IllegalStateException(sb.toString());
122                    }
123                    else if (buildNumber < ReleaseInfo.RELEASE_5_2_3_BUILD_NUMBER) {
124                            String msg = "You must first upgrade to Liferay Portal 5.2.3";
125    
126                            System.out.println(msg);
127    
128                            throw new RuntimeException(msg);
129                    }
130    
131                    // Upgrade
132    
133                    if (_log.isDebugEnabled()) {
134                            _log.debug("Update build " + buildNumber);
135                    }
136    
137                    _checkPermissionAlgorithm();
138                    _checkReleaseState(_getReleaseState());
139    
140                    if (PropsValues.UPGRADE_DATABASE_TRANSACTIONS_DISABLED) {
141                            TransactionsUtil.disableTransactions();
142                    }
143    
144                    try {
145                            StartupHelperUtil.upgradeProcess(buildNumber);
146                    }
147                    catch (Exception e) {
148                            _updateReleaseState(ReleaseConstants.STATE_UPGRADE_FAILURE);
149    
150                            throw e;
151                    }
152                    finally {
153                            if (PropsValues.UPGRADE_DATABASE_TRANSACTIONS_DISABLED) {
154                                    TransactionsUtil.enableTransactions();
155                            }
156                    }
157    
158                    // Reload SQL
159    
160                    CustomSQLUtil.reloadCustomSQL();
161                    SQLTransformer.reloadSQLTransformer();
162    
163                    // Update company key
164    
165                    if (StartupHelperUtil.isUpgraded()) {
166                            if (_log.isDebugEnabled()) {
167                                    _log.debug("Update company key");
168                            }
169    
170                            _updateCompanyKey();
171                    }
172    
173                    // Check class names
174    
175                    if (_log.isDebugEnabled()) {
176                            _log.debug("Check class names");
177                    }
178    
179                    ClassNameLocalServiceUtil.checkClassNames();
180    
181                    // Check resource actions
182    
183                    if (_log.isDebugEnabled()) {
184                            _log.debug("Check resource actions");
185                    }
186    
187                    ResourceActionLocalServiceUtil.checkResourceActions();
188    
189                    // Clear the caches only if the upgrade process was run
190    
191                    if (_log.isDebugEnabled()) {
192                            _log.debug("Clear cache if upgrade process was run");
193                    }
194    
195                    if (StartupHelperUtil.isUpgraded()) {
196                            MultiVMPoolUtil.clear();
197                    }
198            }
199    
200            public static void verify() throws Exception {
201    
202                    // Check release
203    
204                    Release release = ReleaseLocalServiceUtil.fetchRelease(
205                            ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME);
206    
207                    if (release == null) {
208                            release = ReleaseLocalServiceUtil.addRelease(
209                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME,
210                                    ReleaseInfo.getParentBuildNumber());
211                    }
212    
213                    _checkReleaseState(release.getState());
214    
215                    // Update indexes
216    
217                    if (PropsValues.DATABASE_INDEXES_UPDATE_ON_STARTUP) {
218                            StartupHelperUtil.setDropIndexes(true);
219    
220                            StartupHelperUtil.updateIndexes();
221                    }
222                    else if (StartupHelperUtil.isUpgraded()) {
223                            StartupHelperUtil.updateIndexes();
224                    }
225    
226                    // Verify
227    
228                    if (PropsValues.VERIFY_DATABASE_TRANSACTIONS_DISABLED) {
229                            TransactionsUtil.disableTransactions();
230                    }
231    
232                    boolean newBuildNumber = false;
233    
234                    if (ReleaseInfo.getBuildNumber() > release.getBuildNumber()) {
235                            newBuildNumber = true;
236                    }
237    
238                    try {
239                            StartupHelperUtil.verifyProcess(
240                                    newBuildNumber, release.isVerified());
241                    }
242                    catch (Exception e) {
243                            _updateReleaseState(ReleaseConstants.STATE_VERIFY_FAILURE);
244    
245                            _log.error(
246                                    "Unable to execute verify process: " + e.getMessage(), e);
247    
248                            throw e;
249                    }
250                    finally {
251                            if (PropsValues.VERIFY_DATABASE_TRANSACTIONS_DISABLED) {
252                                    TransactionsUtil.enableTransactions();
253                            }
254                    }
255    
256                    // Update indexes
257    
258                    if (PropsValues.DATABASE_INDEXES_UPDATE_ON_STARTUP ||
259                            StartupHelperUtil.isUpgraded()) {
260    
261                            StartupHelperUtil.updateIndexes(false);
262                    }
263    
264                    // Update release
265    
266                    boolean verified = StartupHelperUtil.isVerified();
267    
268                    if (release.isVerified()) {
269                            verified = true;
270                    }
271    
272                    release = ReleaseLocalServiceUtil.updateRelease(
273                            release.getReleaseId(), ReleaseInfo.getParentBuildNumber(),
274                            ReleaseInfo.getBuildDate(), verified);
275    
276                    // Enable database caching after verify
277    
278                    CacheRegistryUtil.setActive(true);
279    
280                    // Register release service
281    
282                    Registry registry = RegistryUtil.getRegistry();
283    
284                    ServiceRegistrar<Release> serviceRegistrar =
285                            registry.getServiceRegistrar(Release.class);
286    
287                    Map<String, Object> properties = new HashMap<>();
288    
289                    properties.put("build.date", release.getBuildDate());
290                    properties.put("build.number", release.getBuildNumber());
291                    properties.put("servlet.context.name", release.getServletContextName());
292    
293                    serviceRegistrar.registerService(Release.class, release, properties);
294            }
295    
296            private static void _checkPermissionAlgorithm() throws Exception {
297                    long count = _getResourceCodesCount();
298    
299                    if (count == 0) {
300                            return;
301                    }
302    
303                    StringBundler sb = new StringBundler(8);
304    
305                    sb.append("Permission conversion to algorithm 6 has not been ");
306                    sb.append("completed. Please complete the conversion prior to ");
307                    sb.append("starting the portal. The conversion process is ");
308                    sb.append("available in portal versions starting with ");
309                    sb.append(ReleaseInfo.RELEASE_5_2_3_BUILD_NUMBER);
310                    sb.append(" and prior to ");
311                    sb.append(ReleaseInfo.RELEASE_6_2_0_BUILD_NUMBER);
312                    sb.append(".");
313    
314                    throw new IllegalStateException(sb.toString());
315            }
316    
317            private static void _checkReleaseState(int state) throws Exception {
318                    if (state == ReleaseConstants.STATE_GOOD) {
319                            return;
320                    }
321    
322                    StringBundler sb = new StringBundler(6);
323    
324                    sb.append("The database contains changes from a previous ");
325                    sb.append("upgrade attempt that failed. Please restore the old ");
326                    sb.append("database and file system and retry the upgrade. A ");
327                    sb.append("patch may be required if the upgrade failed due to a");
328                    sb.append(" bug or an unforeseen data permutation that resulted ");
329                    sb.append("from a corrupt database.");
330    
331                    throw new IllegalStateException(sb.toString());
332            }
333    
334            private static int _getReleaseState() throws Exception {
335                    Connection con = null;
336                    PreparedStatement ps = null;
337                    ResultSet rs = null;
338    
339                    try {
340                            con = DataAccess.getConnection();
341    
342                            ps = con.prepareStatement(
343                                    "select state_ from Release_ where releaseId = ?");
344    
345                            ps.setLong(1, ReleaseConstants.DEFAULT_ID);
346    
347                            rs = ps.executeQuery();
348    
349                            if (rs.next()) {
350                                    return rs.getInt("state_");
351                            }
352    
353                            throw new IllegalArgumentException(
354                                    "No Release exists with the primary key " +
355                                            ReleaseConstants.DEFAULT_ID);
356                    }
357                    finally {
358                            DataAccess.cleanUp(con, ps, rs);
359                    }
360            }
361    
362            private static long _getResourceCodesCount() throws Exception {
363                    Connection con = null;
364                    PreparedStatement ps = null;
365                    ResultSet rs = null;
366    
367                    try {
368                            con = DataAccess.getConnection();
369    
370                            ps = con.prepareStatement("select count(*) from ResourceCode");
371    
372                            rs = ps.executeQuery();
373    
374                            if (rs.next()) {
375                                    int count = rs.getInt(1);
376    
377                                    return count;
378                            }
379    
380                            return 0;
381                    }
382                    catch (Exception e) {
383                            return 0;
384                    }
385                    finally {
386                            DataAccess.cleanUp(con, ps, rs);
387                    }
388            }
389    
390            private static void _updateCompanyKey() throws Exception {
391                    DB db = DBManagerUtil.getDB();
392    
393                    db.runSQL("update Company set key_ = null");
394            }
395    
396            private static void _updateReleaseState(int state) throws Exception {
397                    Connection con = null;
398                    PreparedStatement ps = null;
399    
400                    try {
401                            con = DataAccess.getConnection();
402    
403                            ps = con.prepareStatement(
404                                    "update Release_ set modifiedDate = ?, state_ = ? where " +
405                                            "releaseId = ?");
406    
407                            ps.setDate(1, new Date(System.currentTimeMillis()));
408                            ps.setInt(2, state);
409                            ps.setLong(3, ReleaseConstants.DEFAULT_ID);
410    
411                            ps.executeUpdate();
412                    }
413                    finally {
414                            DataAccess.cleanUp(con, ps);
415                    }
416            }
417    
418            private static final Log _log = LogFactoryUtil.getLog(DBUpgrader.class);
419    
420    }