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