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.NoSuchReleaseException;
018    import com.liferay.portal.events.StartupHelperUtil;
019    import com.liferay.portal.kernel.dao.db.DB;
020    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
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.StringUtil;
032    import com.liferay.portal.kernel.util.Validator;
033    import com.liferay.portal.model.Release;
034    import com.liferay.portal.model.ReleaseConstants;
035    import com.liferay.portal.service.base.ReleaseLocalServiceBaseImpl;
036    import com.liferay.portal.util.PropsUtil;
037    import com.liferay.portal.util.PropsValues;
038    
039    import java.sql.Connection;
040    import java.sql.PreparedStatement;
041    import java.sql.ResultSet;
042    
043    import java.util.Date;
044    import java.util.List;
045    import java.util.Properties;
046    
047    /**
048     * @author Brian Wing Shun Chan
049     */
050    public class ReleaseLocalServiceImpl extends ReleaseLocalServiceBaseImpl {
051    
052            @Override
053            public Release addRelease(String servletContextName, int buildNumber) {
054                    Release release = null;
055    
056                    if (servletContextName.equals(
057                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
058    
059                            release = releasePersistence.create(ReleaseConstants.DEFAULT_ID);
060                    }
061                    else {
062                            long releaseId = counterLocalService.increment();
063    
064                            release = releasePersistence.create(releaseId);
065                    }
066    
067                    Date now = new Date();
068    
069                    release.setCreateDate(now);
070                    release.setModifiedDate(now);
071                    release.setServletContextName(servletContextName);
072                    release.setBuildNumber(buildNumber);
073    
074                    if (servletContextName.equals(
075                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
076    
077                            release.setTestString(ReleaseConstants.TEST_STRING);
078                    }
079    
080                    releasePersistence.update(release);
081    
082                    return release;
083            }
084    
085            @Override
086            public void createTablesAndPopulate() {
087                    try {
088                            if (_log.isInfoEnabled()) {
089                                    _log.info("Create tables and populate with default data");
090                            }
091    
092                            DB db = DBFactoryUtil.getDB();
093    
094                            db.runSQLTemplate("portal-tables.sql", false);
095                            db.runSQLTemplate("portal-data-common.sql", false);
096                            db.runSQLTemplate("portal-data-counter.sql", false);
097                            db.runSQLTemplate("portal-data-release.sql", false);
098                            db.runSQLTemplate("indexes.sql", false);
099                            db.runSQLTemplate("sequences.sql", false);
100    
101                            StartupHelperUtil.setDbNew(true);
102                    }
103                    catch (Exception e) {
104                            _log.error(e, e);
105    
106                            throw new SystemException(e);
107                    }
108            }
109    
110            @Override
111            public Release fetchRelease(String servletContextName) {
112                    if (Validator.isNull(servletContextName)) {
113                            throw new IllegalArgumentException("Servlet context name is null");
114                    }
115    
116                    Release release = null;
117    
118                    if (servletContextName.equals(
119                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME)) {
120    
121                            release = releasePersistence.fetchByPrimaryKey(
122                                    ReleaseConstants.DEFAULT_ID);
123                    }
124                    else {
125                            release = releasePersistence.fetchByServletContextName(
126                                    servletContextName);
127                    }
128    
129                    return release;
130            }
131    
132            @Override
133            public int getBuildNumberOrCreate() throws PortalException {
134    
135                    // Get release build number
136    
137                    Connection con = null;
138                    PreparedStatement ps = null;
139                    ResultSet rs = null;
140    
141                    try {
142                            con = DataAccess.getConnection();
143    
144                            ps = con.prepareStatement(_GET_BUILD_NUMBER);
145    
146                            ps.setLong(1, ReleaseConstants.DEFAULT_ID);
147    
148                            rs = ps.executeQuery();
149    
150                            if (rs.next()) {
151                                    int buildNumber = rs.getInt("buildNumber");
152    
153                                    if (_log.isDebugEnabled()) {
154                                            _log.debug("Build number " + buildNumber);
155                                    }
156    
157                                    DB db = DBFactoryUtil.getDB();
158    
159                                    try {
160                                            db.runSQL("alter table Release_ add state_ INTEGER");
161                                    }
162                                    catch (Exception e) {
163                                            if (_log.isDebugEnabled()) {
164                                                    _log.debug(e.getMessage());
165                                            }
166                                    }
167    
168                                    testSupportsStringCaseSensitiveQuery();
169    
170                                    return buildNumber;
171                            }
172                    }
173                    catch (Exception e) {
174                            if (_log.isWarnEnabled()) {
175                                    _log.warn(e.getMessage());
176                            }
177                    }
178                    finally {
179                            DataAccess.cleanUp(con, ps, rs);
180                    }
181    
182                    // Create tables and populate with default data
183    
184                    if (GetterUtil.getBoolean(
185                                    PropsUtil.get(PropsKeys.SCHEMA_RUN_ENABLED))) {
186    
187                            releaseLocalService.createTablesAndPopulate();
188    
189                            testSupportsStringCaseSensitiveQuery();
190    
191                            Release release = fetchRelease(
192                                    ReleaseConstants.DEFAULT_SERVLET_CONTEXT_NAME);
193    
194                            return release.getBuildNumber();
195                    }
196                    else {
197                            throw new NoSuchReleaseException(
198                                    "The database needs to be populated");
199                    }
200            }
201    
202            @Override
203            public Release updateRelease(
204                            long releaseId, int buildNumber, Date buildDate, boolean verified)
205                    throws PortalException {
206    
207                    Release release = releasePersistence.findByPrimaryKey(releaseId);
208    
209                    release.setModifiedDate(new Date());
210                    release.setBuildNumber(buildNumber);
211                    release.setBuildDate(buildDate);
212                    release.setVerified(verified);
213    
214                    releasePersistence.update(release);
215    
216                    return release;
217            }
218    
219            @Override
220            public void updateRelease(
221                            String servletContextName, List<UpgradeProcess> upgradeProcesses,
222                            int buildNumber, int previousBuildNumber, boolean indexOnUpgrade)
223                    throws PortalException {
224    
225                    if (buildNumber <= 0) {
226                            _log.error(
227                                    "Skipping upgrade processes for " + servletContextName +
228                                            " because \"release.info.build.number\" is not specified");
229    
230                            return;
231                    }
232    
233                    Release release = releaseLocalService.fetchRelease(servletContextName);
234    
235                    if (release == null) {
236                            release = releaseLocalService.addRelease(
237                                    servletContextName, previousBuildNumber);
238                    }
239    
240                    if (buildNumber == release.getBuildNumber()) {
241                            if (_log.isDebugEnabled()) {
242                                    _log.debug(
243                                            "Skipping upgrade processes for " + servletContextName +
244                                                    " because it is already up to date");
245                            }
246                    }
247                    else if (buildNumber < release.getBuildNumber()) {
248                            throw new OlderVersionException(
249                                    "Skipping upgrade processes for " + servletContextName +
250                                            " because you are trying to upgrade with an older version");
251                    }
252                    else {
253                            UpgradeProcessUtil.upgradeProcess(
254                                    release.getBuildNumber(), upgradeProcesses, indexOnUpgrade);
255                    }
256    
257                    releaseLocalService.updateRelease(
258                            release.getReleaseId(), buildNumber, null, true);
259            }
260    
261            @Override
262            public void updateRelease(
263                            String servletContextName, List<UpgradeProcess> upgradeProcesses,
264                            Properties unfilteredPortalProperties)
265                    throws Exception {
266    
267                    int buildNumber = GetterUtil.getInteger(
268                            unfilteredPortalProperties.getProperty(
269                                    PropsKeys.RELEASE_INFO_BUILD_NUMBER));
270                    int previousBuildNumber = GetterUtil.getInteger(
271                            unfilteredPortalProperties.getProperty(
272                                    PropsKeys.RELEASE_INFO_PREVIOUS_BUILD_NUMBER),
273                            buildNumber);
274                    boolean indexOnUpgrade = GetterUtil.getBoolean(
275                            unfilteredPortalProperties.getProperty(PropsKeys.INDEX_ON_UPGRADE),
276                            PropsValues.INDEX_ON_UPGRADE);
277    
278                    updateRelease(
279                            servletContextName, upgradeProcesses, buildNumber,
280                            previousBuildNumber, indexOnUpgrade);
281            }
282    
283            protected void testSupportsStringCaseSensitiveQuery() {
284                    DB db = DBFactoryUtil.getDB();
285    
286                    int count = testSupportsStringCaseSensitiveQuery(
287                            ReleaseConstants.TEST_STRING);
288    
289                    if (count == 0) {
290                            try {
291                                    db.runSQL(
292                                            "alter table Release_ add testString VARCHAR(1024) null");
293                            }
294                            catch (Exception e) {
295                                    if (_log.isDebugEnabled()) {
296                                            _log.debug(e.getMessage());
297                                    }
298                            }
299    
300                            try {
301                                    db.runSQL(
302                                            "update Release_ set testString = '" +
303                                                    ReleaseConstants.TEST_STRING + "'");
304                            }
305                            catch (Exception e) {
306                                    if (_log.isDebugEnabled()) {
307                                            _log.debug(e.getMessage());
308                                    }
309                            }
310    
311                            count = testSupportsStringCaseSensitiveQuery(
312                                    ReleaseConstants.TEST_STRING);
313                    }
314    
315                    if (count == 0) {
316                            throw new SystemException(
317                                    "Release_ table was not initialized properly");
318                    }
319    
320                    count = testSupportsStringCaseSensitiveQuery(
321                            StringUtil.toUpperCase(ReleaseConstants.TEST_STRING));
322    
323                    if (count == 0) {
324                            db.setSupportsStringCaseSensitiveQuery(true);
325                    }
326                    else {
327                            db.setSupportsStringCaseSensitiveQuery(false);
328                    }
329            }
330    
331            protected int testSupportsStringCaseSensitiveQuery(String testString) {
332                    int count = 0;
333    
334                    Connection con = null;
335                    PreparedStatement ps = null;
336                    ResultSet rs = null;
337    
338                    try {
339                            con = DataAccess.getConnection();
340    
341                            ps = con.prepareStatement(_TEST_DATABASE_STRING_CASE_SENSITIVITY);
342    
343                            ps.setLong(1, ReleaseConstants.DEFAULT_ID);
344                            ps.setString(2, testString);
345    
346                            rs = ps.executeQuery();
347    
348                            if (rs.next()) {
349                                    count = rs.getInt(1);
350                            }
351                    }
352                    catch (Exception e) {
353                            if (_log.isWarnEnabled()) {
354                                    _log.warn(e.getMessage());
355                            }
356                    }
357                    finally {
358                            DataAccess.cleanUp(con, ps, rs);
359                    }
360    
361                    return count;
362            }
363    
364            private static final String _GET_BUILD_NUMBER =
365                    "select buildNumber from Release_ where releaseId = ?";
366    
367            private static final String _TEST_DATABASE_STRING_CASE_SENSITIVITY =
368                    "select count(*) from Release_ where releaseId = ? and testString = ?";
369    
370            private static final Log _log = LogFactoryUtil.getLog(
371                    ReleaseLocalServiceImpl.class);
372    
373    }