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