001    /**
002     * Copyright (c) 2000-2013 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.verify;
016    
017    import com.liferay.portal.kernel.dao.db.DB;
018    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
019    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
020    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
021    import com.liferay.portal.kernel.exception.PortalException;
022    import com.liferay.portal.kernel.exception.SystemException;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.HtmlUtil;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.kernel.workflow.WorkflowConstants;
031    import com.liferay.portal.service.ResourceLocalServiceUtil;
032    import com.liferay.portal.util.PortalInstances;
033    import com.liferay.portlet.PortletPreferencesFactoryUtil;
034    import com.liferay.portlet.asset.model.AssetEntry;
035    import com.liferay.portlet.asset.service.AssetEntryLocalServiceUtil;
036    import com.liferay.portlet.dynamicdatamapping.NoSuchStructureException;
037    import com.liferay.portlet.journal.model.JournalArticle;
038    import com.liferay.portlet.journal.model.JournalArticleConstants;
039    import com.liferay.portlet.journal.model.JournalContentSearch;
040    import com.liferay.portlet.journal.model.JournalFolder;
041    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
042    import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
043    import com.liferay.portlet.journal.service.JournalFolderLocalServiceUtil;
044    import com.liferay.portlet.journal.service.persistence.JournalArticleActionableDynamicQuery;
045    
046    import java.sql.Connection;
047    import java.sql.PreparedStatement;
048    import java.sql.ResultSet;
049    
050    import java.util.List;
051    import java.util.regex.Pattern;
052    
053    import javax.portlet.PortletPreferences;
054    
055    /**
056     * @author Alexander Chow
057     * @author Shinn Lok
058     */
059    public class VerifyJournal extends VerifyProcess {
060    
061            public static final long DEFAULT_GROUP_ID = 14;
062    
063            public static final int NUM_OF_ARTICLES = 5;
064    
065            @Override
066            protected void doVerify() throws Exception {
067                    updateFolderAssets();
068                    verifyOracleNewLine();
069                    verifyPermissionsAndAssets();
070                    verifySearch();
071                    verifyTree();
072                    verifyURLTitle();
073            }
074    
075            protected void updateFolderAssets() throws Exception {
076                    List<JournalFolder> folders =
077                            JournalFolderLocalServiceUtil.getNoAssetFolders();
078    
079                    if (_log.isDebugEnabled()) {
080                            _log.debug(
081                                    "Processing " + folders.size() + " folders with no asset");
082                    }
083    
084                    for (JournalFolder folder : folders) {
085                            try {
086                                    JournalFolderLocalServiceUtil.updateAsset(
087                                            folder.getUserId(), folder, null, null, null);
088                            }
089                            catch (Exception e) {
090                                    if (_log.isWarnEnabled()) {
091                                            _log.warn(
092                                                    "Unable to update asset for folder " +
093                                                            folder.getFolderId() + ": " + e.getMessage());
094                                    }
095                            }
096                    }
097    
098                    if (_log.isDebugEnabled()) {
099                            _log.debug("Assets verified for folders");
100                    }
101            }
102    
103            protected void updateURLTitle(
104                            long groupId, String articleId, String urlTitle)
105                    throws Exception {
106    
107                    String normalizedURLTitle = FriendlyURLNormalizerUtil.normalize(
108                            urlTitle, _friendlyURLPattern);
109    
110                    if (urlTitle.equals(normalizedURLTitle)) {
111                            return;
112                    }
113    
114                    normalizedURLTitle = JournalArticleLocalServiceUtil.getUniqueUrlTitle(
115                            groupId, articleId, normalizedURLTitle);
116    
117                    Connection con = null;
118                    PreparedStatement ps = null;
119    
120                    try {
121                            con = DataAccess.getUpgradeOptimizedConnection();
122    
123                            ps = con.prepareStatement(
124                                    "update JournalArticle set urlTitle = ? where urlTitle = ?");
125    
126                            ps.setString(1, normalizedURLTitle);
127                            ps.setString(2, urlTitle);
128    
129                            ps.executeUpdate();
130                    }
131                    finally {
132                            DataAccess.cleanUp(con, ps);
133                    }
134            }
135    
136            protected void verifyContentSearch(long groupId, String portletId)
137                    throws Exception {
138    
139                    Connection con = null;
140                    PreparedStatement ps = null;
141                    ResultSet rs = null;
142    
143                    try {
144                            con = DataAccess.getUpgradeOptimizedConnection();
145    
146                            ps = con.prepareStatement(
147                                    "select preferences from PortletPreferences inner join " +
148                                            "Layout on PortletPreferences.plid = Layout.plid where " +
149                                                    "groupId = ? and portletId = ?");
150    
151                            ps.setLong(1, groupId);
152                            ps.setString(2, portletId);
153    
154                            rs = ps.executeQuery();
155    
156                            while (rs.next()) {
157                                    String xml = rs.getString("preferences");
158    
159                                    PortletPreferences portletPreferences =
160                                            PortletPreferencesFactoryUtil.fromDefaultXML(xml);
161    
162                                    String articleId = portletPreferences.getValue(
163                                            "articleId", null);
164    
165                                    List<JournalContentSearch> contentSearches =
166                                            JournalContentSearchLocalServiceUtil.
167                                                    getArticleContentSearches(groupId, articleId);
168    
169                                    if (contentSearches.isEmpty()) {
170                                            continue;
171                                    }
172    
173                                    JournalContentSearch contentSearch = contentSearches.get(0);
174    
175                                    JournalContentSearchLocalServiceUtil.updateContentSearch(
176                                            contentSearch.getGroupId(), contentSearch.isPrivateLayout(),
177                                            contentSearch.getLayoutId(), contentSearch.getPortletId(),
178                                            articleId, true);
179                            }
180                    }
181                    finally {
182                            DataAccess.cleanUp(con, ps, rs);
183                    }
184            }
185    
186            protected void verifyOracleNewLine() throws Exception {
187                    DB db = DBFactoryUtil.getDB();
188    
189                    String dbType = db.getType();
190    
191                    if (!dbType.equals(DB.TYPE_ORACLE)) {
192                            return;
193                    }
194    
195                    // This is a workaround for a limitation in Oracle sqlldr's inability
196                    // insert new line characters for long varchar columns. See
197                    // http://forums.liferay.com/index.php?showtopic=2761&hl=oracle for more
198                    // information. Check several articles because some articles may not
199                    // have new lines.
200    
201                    boolean checkNewLine = false;
202    
203                    List<JournalArticle> articles =
204                            JournalArticleLocalServiceUtil.getArticles(
205                                    DEFAULT_GROUP_ID, 0, NUM_OF_ARTICLES);
206    
207                    for (JournalArticle article : articles) {
208                            String content = article.getContent();
209    
210                            if ((content != null) && content.contains("\\n")) {
211                                    articles = JournalArticleLocalServiceUtil.getArticles(
212                                            DEFAULT_GROUP_ID);
213    
214                                    for (int j = 0; j < articles.size(); j++) {
215                                            article = articles.get(j);
216    
217                                            JournalArticleLocalServiceUtil.checkNewLine(
218                                                    article.getGroupId(), article.getArticleId(),
219                                                    article.getVersion());
220                                    }
221    
222                                    checkNewLine = true;
223    
224                                    break;
225                            }
226                    }
227    
228                    // Only process this once
229    
230                    if (!checkNewLine) {
231                            if (_log.isInfoEnabled()) {
232                                    _log.info("Do not fix oracle new line");
233                            }
234    
235                            return;
236                    }
237                    else {
238                            if (_log.isInfoEnabled()) {
239                                    _log.info("Fix oracle new line");
240                            }
241                    }
242            }
243    
244            protected void verifyPermissionsAndAssets() throws Exception {
245                    ActionableDynamicQuery actionableDynamicQuery =
246                            new JournalArticleActionableDynamicQuery() {
247    
248                            @Override
249                            protected void performAction(Object object)
250                                    throws PortalException, SystemException {
251    
252                                    JournalArticle article = (JournalArticle)object;
253    
254                                    long groupId = article.getGroupId();
255                                    String articleId = article.getArticleId();
256                                    double version = article.getVersion();
257                                    String structureId = article.getStructureId();
258    
259                                    if (article.getResourcePrimKey() <= 0) {
260                                            article =
261                                                    JournalArticleLocalServiceUtil.
262                                                            checkArticleResourcePrimKey(
263                                                                    groupId, articleId, version);
264                                    }
265    
266                                    ResourceLocalServiceUtil.addResources(
267                                            article.getCompanyId(), 0, 0,
268                                            JournalArticle.class.getName(),
269                                            article.getResourcePrimKey(), false, false, false);
270    
271                                    AssetEntry assetEntry = AssetEntryLocalServiceUtil.fetchEntry(
272                                            JournalArticle.class.getName(),
273                                            article.getResourcePrimKey());
274    
275                                    if (assetEntry == null) {
276                                            try {
277                                                    JournalArticleLocalServiceUtil.updateAsset(
278                                                            article.getUserId(), article, null, null, null);
279                                            }
280                                            catch (Exception e) {
281                                                    if (_log.isWarnEnabled()) {
282                                                            _log.warn(
283                                                                    "Unable to update asset for article " +
284                                                                            article.getId() + ": " + e.getMessage());
285                                                    }
286                                            }
287                                    }
288                                    else if ((article.getStatus() ==
289                                                            WorkflowConstants.STATUS_DRAFT) &&
290                                                     (article.getVersion() ==
291                                                            JournalArticleConstants.VERSION_DEFAULT)) {
292    
293                                            AssetEntryLocalServiceUtil.updateEntry(
294                                                    assetEntry.getClassName(), assetEntry.getClassPK(),
295                                                    null, assetEntry.isVisible());
296                                    }
297    
298                                    String content = GetterUtil.getString(article.getContent());
299    
300                                    String newContent = HtmlUtil.replaceMsWordCharacters(content);
301    
302                                    if (Validator.isNotNull(structureId)) {
303                                            /*JournalStructure structure =
304                                                    JournalStructureLocalServiceUtil.getStructure(
305                                                            groupId, structureId);
306    
307                                            newContent = JournalUtil.removeOldContent(
308                                                    newContent, structure.getXsd());*/
309                                    }
310    
311                                    if (!content.equals(newContent)) {
312                                            JournalArticleLocalServiceUtil.updateContent(
313                                                    groupId, articleId, version, newContent);
314                                    }
315    
316                                    try {
317                                            JournalArticleLocalServiceUtil.checkStructure(
318                                                    groupId, articleId, version);
319                                    }
320                                    catch (NoSuchStructureException nsse) {
321                                            if (_log.isWarnEnabled()) {
322                                                    _log.warn(
323                                                            "Removing reference to missing structure for " +
324                                                                    "article " + article.getId());
325                                            }
326    
327                                            article.setStructureId(StringPool.BLANK);
328                                            article.setTemplateId(StringPool.BLANK);
329    
330                                            JournalArticleLocalServiceUtil.updateJournalArticle(
331                                                    article);
332                                    }
333                            }
334    
335                    };
336    
337                    actionableDynamicQuery.performActions();
338    
339                    if (_log.isDebugEnabled()) {
340                            _log.debug("Permissions and assets verified for articles");
341                    }
342            }
343    
344            protected void verifySearch() throws Exception {
345                    Connection con = null;
346                    PreparedStatement ps = null;
347                    ResultSet rs = null;
348    
349                    try {
350                            con = DataAccess.getUpgradeOptimizedConnection();
351    
352                            ps = con.prepareStatement(
353                                    "select groupId, portletId from JournalContentSearch group " +
354                                            "by groupId, portletId having count(groupId) > 1 and " +
355                                                    "count(portletId) > 1");
356    
357                            rs = ps.executeQuery();
358    
359                            while (rs.next()) {
360                                    long groupId = rs.getLong("groupId");
361                                    String portletId = rs.getString("portletId");
362    
363                                    verifyContentSearch(groupId, portletId);
364                            }
365                    }
366                    finally {
367                            DataAccess.cleanUp(con, ps, rs);
368                    }
369            }
370    
371            protected void verifyTree() throws Exception {
372                    long[] companyIds = PortalInstances.getCompanyIdsBySQL();
373    
374                    for (long companyId : companyIds) {
375                            JournalArticleLocalServiceUtil.rebuildTree(companyId);
376                            JournalFolderLocalServiceUtil.rebuildTree(companyId);
377                    }
378            }
379    
380            protected void verifyURLTitle() throws Exception {
381                    Connection con = null;
382                    PreparedStatement ps = null;
383                    ResultSet rs = null;
384    
385                    try {
386                            con = DataAccess.getUpgradeOptimizedConnection();
387    
388                            ps = con.prepareStatement(
389                                    "select distinct groupId, articleId, urlTitle from " +
390                                            "JournalArticle");
391    
392                            rs = ps.executeQuery();
393    
394                            while (rs.next()) {
395                                    long groupId = rs.getLong("groupId");
396                                    String articleId = rs.getString("articleId");
397                                    String urlTitle = rs.getString("urlTitle");
398    
399                                    updateURLTitle(groupId, articleId, urlTitle);
400                            }
401                    }
402                    finally {
403                            DataAccess.cleanUp(con, ps, rs);
404                    }
405            }
406    
407            private static Log _log = LogFactoryUtil.getLog(VerifyJournal.class);
408    
409            private static Pattern _friendlyURLPattern = Pattern.compile("[^a-z0-9_-]");
410    
411    }