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.service.impl;
016    
017    import com.liferay.portal.events.StartupHelperUtil;
018    import com.liferay.portal.exception.NoSuchReleaseException;
019    import com.liferay.portal.kernel.dao.db.DB;
020    import com.liferay.portal.kernel.dao.db.DBManagerUtil;
021    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
022    import com.liferay.portal.kernel.exception.PortalException;
023    import com.liferay.portal.kernel.exception.SystemException;
024    import com.liferay.portal.kernel.log.Log;
025    import com.liferay.portal.kernel.log.LogFactoryUtil;
026    import com.liferay.portal.kernel.upgrade.OlderVersionException;
027    import com.liferay.portal.kernel.upgrade.UpgradeProcess;
028    import com.liferay.portal.kernel.upgrade.util.UpgradeProcessUtil;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.PropsKeys;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.model.Release;
035    import com.liferay.portal.model.ReleaseConstants;
036    import com.liferay.portal.service.base.ReleaseLocalServiceBaseImpl;
037    import com.liferay.portal.util.PropsUtil;
038    import com.liferay.portal.util.PropsValues;
039    
040    import java.sql.Connection;
041    import java.sql.PreparedStatement;
042    import java.sql.ResultSet;
043    
044    import java.util.Date;
045    import java.util.List;
046    import java.util.Properties;
047    
048    /**
049     * @author Brian Wing Shun Chan
050     */
051    public class ReleaseLocalServiceImpl extends ReleaseLocalServiceBaseImpl {
052    
053            @Override
054            public Release addRelease(String servletContextName, int buildNumber) {
055                    Release release = null;
056    
057                    if (servletContextName.equals(
058                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
059    
060                            release = releasePersistence.create(ReleaseConstants.DEFAULT_ID);
061                    }
062                    else {
063                            long releaseId = counterLocalService.increment();
064    
065                            release = releasePersistence.create(releaseId);
066                    }
067    
068                    Date now = new Date();
069    
070                    release.setCreateDate(now);
071                    release.setModifiedDate(now);
072                    release.setServletContextName(servletContextName);
073                    release.setBuildNumber(buildNumber);
074    
075                    if (servletContextName.equals(
076                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
077    
078                            release.setTestString(ReleaseConstants.TEST_STRING);
079                    }
080    
081                    releasePersistence.update(release);
082    
083                    return release;
084            }
085    
086            @Override
087            public Release addRelease(String servletContextName, String schemaVersion) {
088                    Release release = null;
089    
090                    if (servletContextName.equals(
091                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
092    
093                            release = releasePersistence.create(ReleaseConstants.DEFAULT_ID);
094                    }
095    
096                    else {
097                            long releaseId = counterLocalService.increment();
098    
099                            release = releasePersistence.create(releaseId);
100                    }
101    
102                    Date now = new Date();
103    
104                    release.setCreateDate(now);
105                    release.setModifiedDate(now);
106                    release.setServletContextName(servletContextName);
107                    release.setSchemaVersion(schemaVersion);
108    
109                    if (servletContextName.equals(
110                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
111    
112                            release.setTestString(ReleaseConstants.TEST_STRING);
113                    }
114    
115                    releasePersistence.update(release);
116    
117                    return release;
118            }
119    
120            @Override
121            public void createTablesAndPopulate() {
122                    try {
123                            if (_log.isInfoEnabled()) {
124                                    _log.info("Create tables and populate with default data");
125                            }
126    
127                            DB db = DBManagerUtil.getDB();
128    
129                            db.runSQLTemplate("portal-tables.sql", false);
130                            db.runSQLTemplate("portal-data-common.sql", false);
131                            db.runSQLTemplate("portal-data-counter.sql", false);
132                            db.runSQLTemplate("portal-data-release.sql", false);
133                            db.runSQLTemplate("indexes.sql", false);
134                            db.runSQLTemplate("sequences.sql", false);
135    
136                            StartupHelperUtil.setDbNew(true);
137                    }
138                    catch (Exception e) {
139                            _log.error(e, e);
140    
141                            throw new SystemException(e);
142                    }
143            }
144    
145            @Override
146            public Release fetchRelease(String servletContextName) {
147                    if (Validator.isNull(servletContextName)) {
148                            throw new IllegalArgumentException("Servlet context name is null");
149                    }
150    
151                    Release release = null;
152    
153                    if (servletContextName.equals(
154                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
155    
156                            release = releasePersistence.fetchByPrimaryKey(
157                                    ReleaseConstants.DEFAULT_ID);
158                    }
159                    else {
160                            release = releasePersistence.fetchByServletContextName(
161                                    servletContextName);
162                    }
163    
164                    return release;
165            }
166    
167            @Override
168            public int getBuildNumberOrCreate() throws PortalException {
169    
170                    // Gracefully add version column
171    
172                    DB db = DBManagerUtil.getDB();
173    
174                    try {
175                            db.runSQL(
176                                    "alter table Release_ add schemaVersion VARCHAR(75) null");
177    
178                            populateVersion();
179                    }
180                    catch (Exception e) {
181                            if (_log.isDebugEnabled()) {
182                                    _log.debug(e.getMessage());
183                            }
184                    }
185    
186                    // Get release build number
187    
188                    Connection con = null;
189                    PreparedStatement ps = null;
190                    ResultSet rs = null;
191    
192                    try {
193                            con = DataAccess.getConnection();
194    
195                            ps = con.prepareStatement(_GET_BUILD_NUMBER);
196    
197                            ps.setLong(1, ReleaseConstants.DEFAULT_ID);
198    
199                            rs = ps.executeQuery();
200    
201                            if (rs.next()) {
202                                    int buildNumber = rs.getInt("buildNumber");
203    
204                                    if (_log.isDebugEnabled()) {
205                                            _log.debug("Build number " + buildNumber);
206                                    }
207    
208                                    // Gracefully add state_ column
209    
210                                    try {
211                                            db.runSQL("alter table Release_ add state_ INTEGER");
212                                    }
213                                    catch (Exception e) {
214                                            if (_log.isDebugEnabled()) {
215                                                    _log.debug(e.getMessage());
216                                            }
217                                    }
218    
219                                    testSupportsStringCaseSensitiveQuery();
220    
221                                    return buildNumber;
222                            }
223                    }
224                    catch (Exception e) {
225                            if (_log.isWarnEnabled()) {
226                                    _log.warn(e.getMessage());
227                            }
228                    }
229                    finally {
230                            DataAccess.cleanUp(con, ps, rs);
231                    }
232    
233                    // Create tables and populate with default data
234    
235                    if (GetterUtil.getBoolean(
236                                    PropsUtil.get(PropsKeys.SCHEMA_RUN_ENABLED))) {
237    
238                            releaseLocalService.createTablesAndPopulate();
239    
240                            testSupportsStringCaseSensitiveQuery();
241    
242                            Release release = fetchRelease(
243                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME);
244    
245                            return release.getBuildNumber();
246                    }
247                    else {
248                            throw new NoSuchReleaseException(
249                                    "The database needs to be populated");
250                    }
251            }
252    
253            @Override
254            public Release updateRelease(
255                            long releaseId, int buildNumber, Date buildDate, boolean verified)
256                    throws PortalException {
257    
258                    Release release = releasePersistence.findByPrimaryKey(releaseId);
259    
260                    release.setModifiedDate(new Date());
261                    release.setBuildNumber(buildNumber);
262                    release.setBuildDate(buildDate);
263                    release.setVerified(verified);
264    
265                    releasePersistence.update(release);
266    
267                    return release;
268            }
269    
270            @Override
271            public void updateRelease(
272                            String servletContextName, List<UpgradeProcess> upgradeProcesses,
273                            int buildNumber, int previousBuildNumber, boolean indexOnUpgrade)
274                    throws PortalException {
275    
276                    if (buildNumber <= 0) {
277                            _log.error(
278                                    "Skipping upgrade processes for " + servletContextName +
279                                            " because \"release.info.build.number\" is not specified");
280    
281                            return;
282                    }
283    
284                    Release release = releaseLocalService.fetchRelease(servletContextName);
285    
286                    if (release == null) {
287                            release = releaseLocalService.addRelease(
288                                    servletContextName, previousBuildNumber);
289                    }
290    
291                    if (buildNumber == release.getBuildNumber()) {
292                            if (_log.isDebugEnabled()) {
293                                    _log.debug(
294                                            "Skipping upgrade processes for " + servletContextName +
295                                                    " because it is already up to date");
296                            }
297                    }
298                    else if (buildNumber < release.getBuildNumber()) {
299                            throw new OlderVersionException(
300                                    "Skipping upgrade processes for " + servletContextName +
301                                            " because you are trying to upgrade with an older version");
302                    }
303                    else {
304                            UpgradeProcessUtil.upgradeProcess(
305                                    release.getBuildNumber(), upgradeProcesses, indexOnUpgrade);
306                    }
307    
308                    releaseLocalService.updateRelease(
309                            release.getReleaseId(), buildNumber, null, true);
310            }
311    
312            @Override
313            public void updateRelease(
314                            String servletContextName, List<UpgradeProcess> upgradeProcesses,
315                            Properties unfilteredPortalProperties)
316                    throws Exception {
317    
318                    int buildNumber = GetterUtil.getInteger(
319                            unfilteredPortalProperties.getProperty(
320                                    PropsKeys.RELEASE_INFO_BUILD_NUMBER));
321                    int previousBuildNumber = GetterUtil.getInteger(
322                            unfilteredPortalProperties.getProperty(
323                                    PropsKeys.RELEASE_INFO_PREVIOUS_BUILD_NUMBER),
324                            buildNumber);
325                    boolean indexOnUpgrade = GetterUtil.getBoolean(
326                            unfilteredPortalProperties.getProperty(PropsKeys.INDEX_ON_UPGRADE),
327                            PropsValues.INDEX_ON_UPGRADE);
328    
329                    updateRelease(
330                            servletContextName, upgradeProcesses, buildNumber,
331                            previousBuildNumber, indexOnUpgrade);
332            }
333    
334            @Override
335            public void updateRelease(
336                    String servletContextName, String schemaVersion,
337                    String previousSchemaVersion) {
338    
339                    Release release = releaseLocalService.fetchRelease(servletContextName);
340    
341                    if (release == null) {
342                            if (previousSchemaVersion.equals("0.0.0")) {
343                                    release = releaseLocalService.addRelease(
344                                            servletContextName, previousSchemaVersion);
345                            }
346                            else {
347                                    throw new IllegalStateException(
348                                            "Unable to update release because it does not exist");
349                            }
350                    }
351    
352                    String currentSchemaVersion = release.getSchemaVersion();
353    
354                    if (Validator.isNull(currentSchemaVersion)) {
355                            currentSchemaVersion = "0.0.0";
356                    }
357    
358                    if (!previousSchemaVersion.equals(currentSchemaVersion)) {
359                            StringBundler sb = new StringBundler(5);
360    
361                            sb.append("Unable to update release because the previous schema ");
362                            sb.append("version ");
363                            sb.append(previousSchemaVersion);
364                            sb.append(" does not match the expected schema version ");
365                            sb.append(currentSchemaVersion);
366    
367                            throw new IllegalStateException(sb.toString());
368                    }
369    
370                    release.setSchemaVersion(schemaVersion);
371    
372                    releasePersistence.update(release);
373            }
374    
375            protected void populateVersion() {
376    
377                    // This method is called if and only if the version column did not
378                    // previously exist and was safely added to the database
379    
380            }
381    
382            protected void testSupportsStringCaseSensitiveQuery() {
383                    DB db = DBManagerUtil.getDB();
384    
385                    int count = testSupportsStringCaseSensitiveQuery(
386                            ReleaseConstants.TEST_STRING);
387    
388                    if (count == 0) {
389                            try {
390                                    db.runSQL(
391                                            "alter table Release_ add testString VARCHAR(1024) null");
392                            }
393                            catch (Exception e) {
394                                    if (_log.isDebugEnabled()) {
395                                            _log.debug(e.getMessage());
396                                    }
397                            }
398    
399                            try {
400                                    db.runSQL(
401                                            "update Release_ set testString = '" +
402                                                    ReleaseConstants.TEST_STRING + "'");
403                            }
404                            catch (Exception e) {
405                                    if (_log.isDebugEnabled()) {
406                                            _log.debug(e.getMessage());
407                                    }
408                            }
409    
410                            count = testSupportsStringCaseSensitiveQuery(
411                                    ReleaseConstants.TEST_STRING);
412                    }
413    
414                    if (count == 0) {
415                            throw new SystemException(
416                                    "Release_ table was not initialized properly");
417                    }
418    
419                    count = testSupportsStringCaseSensitiveQuery(
420                            StringUtil.toUpperCase(ReleaseConstants.TEST_STRING));
421    
422                    if (count == 0) {
423                            db.setSupportsStringCaseSensitiveQuery(true);
424                    }
425                    else {
426                            db.setSupportsStringCaseSensitiveQuery(false);
427                    }
428            }
429    
430            protected int testSupportsStringCaseSensitiveQuery(String testString) {
431                    int count = 0;
432    
433                    Connection con = null;
434                    PreparedStatement ps = null;
435                    ResultSet rs = null;
436    
437                    try {
438                            con = DataAccess.getConnection();
439    
440                            ps = con.prepareStatement(_TEST_DATABASE_STRING_CASE_SENSITIVITY);
441    
442                            ps.setLong(1, ReleaseConstants.DEFAULT_ID);
443                            ps.setString(2, testString);
444    
445                            rs = ps.executeQuery();
446    
447                            if (rs.next()) {
448                                    count = rs.getInt(1);
449                            }
450                    }
451                    catch (Exception e) {
452                            if (_log.isWarnEnabled()) {
453                                    _log.warn(e.getMessage());
454                            }
455                    }
456                    finally {
457                            DataAccess.cleanUp(con, ps, rs);
458                    }
459    
460                    return count;
461            }
462    
463            private static final String _GET_BUILD_NUMBER =
464                    "select buildNumber from Release_ where releaseId = ?";
465    
466            private static final String _TEST_DATABASE_STRING_CASE_SENSITIVITY =
467                    "select count(*) from Release_ where releaseId = ? and testString = ?";
468    
469            private static final Log _log = LogFactoryUtil.getLog(
470                    ReleaseLocalServiceImpl.class);
471    
472    }