001
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.dao.orm.QueryUtil;
022 import com.liferay.portal.kernel.exception.PortalException;
023 import com.liferay.portal.kernel.log.Log;
024 import com.liferay.portal.kernel.log.LogFactoryUtil;
025 import com.liferay.portal.kernel.util.CharPool;
026 import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
027 import com.liferay.portal.kernel.util.GetterUtil;
028 import com.liferay.portal.kernel.util.HtmlUtil;
029 import com.liferay.portal.kernel.util.HttpUtil;
030 import com.liferay.portal.kernel.util.StringPool;
031 import com.liferay.portal.kernel.util.StringUtil;
032 import com.liferay.portal.kernel.workflow.WorkflowConstants;
033 import com.liferay.portal.kernel.xml.Document;
034 import com.liferay.portal.kernel.xml.Element;
035 import com.liferay.portal.kernel.xml.Node;
036 import com.liferay.portal.kernel.xml.SAXReaderUtil;
037 import com.liferay.portal.service.ResourceLocalServiceUtil;
038 import com.liferay.portal.util.PortalInstances;
039 import com.liferay.portlet.PortletPreferencesFactoryUtil;
040 import com.liferay.portlet.asset.model.AssetEntry;
041 import com.liferay.portlet.asset.service.AssetEntryLocalServiceUtil;
042 import com.liferay.portlet.documentlibrary.model.DLFileEntry;
043 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
044 import com.liferay.portlet.dynamicdatamapping.NoSuchStructureException;
045 import com.liferay.portlet.journal.model.JournalArticle;
046 import com.liferay.portlet.journal.model.JournalArticleConstants;
047 import com.liferay.portlet.journal.model.JournalArticleResource;
048 import com.liferay.portlet.journal.model.JournalContentSearch;
049 import com.liferay.portlet.journal.model.JournalFolder;
050 import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
051 import com.liferay.portlet.journal.service.JournalArticleResourceLocalServiceUtil;
052 import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
053 import com.liferay.portlet.journal.service.JournalFolderLocalServiceUtil;
054 import com.liferay.portlet.journal.util.comparator.ArticleVersionComparator;
055
056 import java.sql.Connection;
057 import java.sql.PreparedStatement;
058 import java.sql.ResultSet;
059
060 import java.util.Date;
061 import java.util.List;
062 import java.util.regex.Pattern;
063
064 import javax.portlet.PortletPreferences;
065
066
070 public class VerifyJournal extends VerifyProcess {
071
072 public static final long DEFAULT_GROUP_ID = 14;
073
074 public static final int NUM_OF_ARTICLES = 5;
075
076 @Override
077 protected void doVerify() throws Exception {
078 verifyContent();
079 verifyCreateDate();
080 updateFolderAssets();
081 verifyOracleNewLine();
082 verifyPermissionsAndAssets();
083 verifySearch();
084 verifyTree();
085 verifyURLTitle();
086 }
087
088 protected void updateDocumentLibraryElements(Element element) {
089 List<Element> dynamicElementElements = element.elements(
090 "dynamic-element");
091
092 for (Element dynamicElementElement : dynamicElementElements) {
093 updateDocumentLibraryElements(dynamicElementElement);
094 }
095
096 Element dynamicContentElement = element.element("dynamic-content");
097
098 String path = dynamicContentElement.getStringValue();
099
100 String[] pathArray = StringUtil.split(path, CharPool.SLASH);
101
102 if (pathArray.length != 5) {
103 return;
104 }
105
106 long groupId = GetterUtil.getLong(pathArray[2]);
107 long folderId = GetterUtil.getLong(pathArray[3]);
108 String title = HttpUtil.decodeURL(HtmlUtil.escape(pathArray[4]));
109
110 DLFileEntry dlFileEntry = DLFileEntryLocalServiceUtil.fetchFileEntry(
111 groupId, folderId, title);
112
113 if (dlFileEntry == null) {
114 return;
115 }
116
117 Node node = dynamicContentElement.node(0);
118
119 node.setText(path + StringPool.SLASH + dlFileEntry.getUuid());
120 }
121
122 protected void updateFolderAssets() throws Exception {
123 List<JournalFolder> folders =
124 JournalFolderLocalServiceUtil.getNoAssetFolders();
125
126 if (_log.isDebugEnabled()) {
127 _log.debug(
128 "Processing " + folders.size() + " folders with no asset");
129 }
130
131 for (JournalFolder folder : folders) {
132 try {
133 JournalFolderLocalServiceUtil.updateAsset(
134 folder.getUserId(), folder, null, null, null);
135 }
136 catch (Exception e) {
137 if (_log.isWarnEnabled()) {
138 _log.warn(
139 "Unable to update asset for folder " +
140 folder.getFolderId() + ": " + e.getMessage());
141 }
142 }
143 }
144
145 if (_log.isDebugEnabled()) {
146 _log.debug("Assets verified for folders");
147 }
148 }
149
150 protected void updateLinkToLayoutElements(long groupId, Element element) {
151 List<Element> dynamicElementElements = element.elements(
152 "dynamic-element");
153
154 for (Element dynamicElementElement : dynamicElementElements) {
155 updateLinkToLayoutElements(groupId, dynamicElementElement);
156 }
157
158 Element dynamicContentElement = element.element("dynamic-content");
159
160 Node node = dynamicContentElement.node(0);
161
162 node.setText(
163 dynamicContentElement.getStringValue() + StringPool.AT + groupId);
164 }
165
166 protected void updateURLTitle(
167 long groupId, String articleId, String urlTitle)
168 throws Exception {
169
170 String normalizedURLTitle = FriendlyURLNormalizerUtil.normalize(
171 urlTitle, _friendlyURLPattern);
172
173 if (urlTitle.equals(normalizedURLTitle)) {
174 return;
175 }
176
177 normalizedURLTitle = JournalArticleLocalServiceUtil.getUniqueUrlTitle(
178 groupId, articleId, normalizedURLTitle);
179
180 Connection con = null;
181 PreparedStatement ps = null;
182
183 try {
184 con = DataAccess.getUpgradeOptimizedConnection();
185
186 ps = con.prepareStatement(
187 "update JournalArticle set urlTitle = ? where urlTitle = ?");
188
189 ps.setString(1, normalizedURLTitle);
190 ps.setString(2, urlTitle);
191
192 ps.executeUpdate();
193 }
194 finally {
195 DataAccess.cleanUp(con, ps);
196 }
197 }
198
199 protected void verifyContent() throws Exception {
200 Connection con = null;
201 PreparedStatement ps = null;
202 ResultSet rs = null;
203
204 try {
205 con = DataAccess.getUpgradeOptimizedConnection();
206
207 ps = con.prepareStatement(
208 "select id_ from JournalArticle where (content like " +
209 "'%document_library%' or content like '%link_to_layout%')" +
210 " and structureId != ''");
211
212 rs = ps.executeQuery();
213
214 while (rs.next()) {
215 long id = rs.getLong("id_");
216
217 JournalArticle article =
218 JournalArticleLocalServiceUtil.getArticle(id);
219
220 Document document = SAXReaderUtil.read(article.getContent());
221
222 Element rootElement = document.getRootElement();
223
224 for (Element element : rootElement.elements()) {
225 String type = element.attributeValue("type");
226
227 if (type.equals("document_library")) {
228 updateDocumentLibraryElements(element);
229 }
230 else if (type.equals("link_to_layout")) {
231 updateLinkToLayoutElements(
232 article.getGroupId(), element);
233 }
234 }
235
236 article.setContent(document.asXML());
237
238 JournalArticleLocalServiceUtil.updateJournalArticle(article);
239 }
240 }
241 finally {
242 DataAccess.cleanUp(con, ps, rs);
243 }
244 }
245
246 protected void verifyContentSearch(long groupId, String portletId)
247 throws Exception {
248
249 Connection con = null;
250 PreparedStatement ps = null;
251 ResultSet rs = null;
252
253 try {
254 con = DataAccess.getUpgradeOptimizedConnection();
255
256 ps = con.prepareStatement(
257 "select preferences from PortletPreferences inner join " +
258 "Layout on PortletPreferences.plid = Layout.plid where " +
259 "groupId = ? and portletId = ?");
260
261 ps.setLong(1, groupId);
262 ps.setString(2, portletId);
263
264 rs = ps.executeQuery();
265
266 while (rs.next()) {
267 String xml = rs.getString("preferences");
268
269 PortletPreferences portletPreferences =
270 PortletPreferencesFactoryUtil.fromDefaultXML(xml);
271
272 String articleId = portletPreferences.getValue(
273 "articleId", null);
274
275 List<JournalContentSearch> contentSearches =
276 JournalContentSearchLocalServiceUtil.
277 getArticleContentSearches(groupId, articleId);
278
279 if (contentSearches.isEmpty()) {
280 continue;
281 }
282
283 JournalContentSearch contentSearch = contentSearches.get(0);
284
285 JournalContentSearchLocalServiceUtil.updateContentSearch(
286 contentSearch.getGroupId(), contentSearch.isPrivateLayout(),
287 contentSearch.getLayoutId(), contentSearch.getPortletId(),
288 articleId, true);
289 }
290 }
291 finally {
292 DataAccess.cleanUp(con, ps, rs);
293 }
294 }
295
296 protected void verifyCreateDate() throws Exception {
297 ActionableDynamicQuery actionableDynamicQuery =
298 JournalArticleResourceLocalServiceUtil.getActionableDynamicQuery();
299
300 actionableDynamicQuery.setPerformActionMethod(
301 new ActionableDynamicQuery.PerformActionMethod() {
302
303 @Override
304 public void performAction(Object object) {
305 JournalArticleResource articleResource =
306 (JournalArticleResource)object;
307
308 verifyCreateDate(articleResource);
309 }
310
311 });
312
313 actionableDynamicQuery.performActions();
314
315 if (_log.isDebugEnabled()) {
316 _log.debug("Create dates verified for articles");
317 }
318 }
319
320 protected void verifyCreateDate(JournalArticleResource articleResource) {
321 List<JournalArticle> articles =
322 JournalArticleLocalServiceUtil.getArticles(
323 articleResource.getGroupId(), articleResource.getArticleId(),
324 QueryUtil.ALL_POS, QueryUtil.ALL_POS,
325 new ArticleVersionComparator(true));
326
327 if (articles.size() <= 1) {
328 return;
329 }
330
331 JournalArticle firstArticle = articles.get(0);
332
333 Date createDate = firstArticle.getCreateDate();
334
335 for (JournalArticle article : articles) {
336 if (!createDate.equals(article.getCreateDate())) {
337 article.setCreateDate(createDate);
338
339 JournalArticleLocalServiceUtil.updateJournalArticle(article);
340 }
341 }
342 }
343
344 protected void verifyOracleNewLine() throws Exception {
345 DB db = DBFactoryUtil.getDB();
346
347 String dbType = db.getType();
348
349 if (!dbType.equals(DB.TYPE_ORACLE)) {
350 return;
351 }
352
353
354
355
356
357
358
359 boolean checkNewLine = false;
360
361 List<JournalArticle> articles =
362 JournalArticleLocalServiceUtil.getArticles(
363 DEFAULT_GROUP_ID, 0, NUM_OF_ARTICLES);
364
365 for (JournalArticle article : articles) {
366 String content = article.getContent();
367
368 if ((content != null) && content.contains("\\n")) {
369 articles = JournalArticleLocalServiceUtil.getArticles(
370 DEFAULT_GROUP_ID);
371
372 for (int j = 0; j < articles.size(); j++) {
373 article = articles.get(j);
374
375 JournalArticleLocalServiceUtil.checkNewLine(
376 article.getGroupId(), article.getArticleId(),
377 article.getVersion());
378 }
379
380 checkNewLine = true;
381
382 break;
383 }
384 }
385
386
387
388 if (!checkNewLine) {
389 if (_log.isInfoEnabled()) {
390 _log.info("Do not fix oracle new line");
391 }
392
393 return;
394 }
395 else {
396 if (_log.isInfoEnabled()) {
397 _log.info("Fix oracle new line");
398 }
399 }
400 }
401
402 protected void verifyPermissionsAndAssets() throws Exception {
403 ActionableDynamicQuery actionableDynamicQuery =
404 JournalArticleLocalServiceUtil.getActionableDynamicQuery();
405
406 actionableDynamicQuery.setPerformActionMethod(
407 new ActionableDynamicQuery.PerformActionMethod() {
408
409 @Override
410 public void performAction(Object object)
411 throws PortalException {
412
413 JournalArticle article = (JournalArticle)object;
414
415 verifyPermissionsAndAssets(article);
416 }
417
418 });
419
420 actionableDynamicQuery.performActions();
421
422 if (_log.isDebugEnabled()) {
423 _log.debug("Permissions and assets verified for articles");
424 }
425 }
426
427 protected void verifyPermissionsAndAssets(JournalArticle article)
428 throws PortalException {
429
430 long groupId = article.getGroupId();
431 String articleId = article.getArticleId();
432 double version = article.getVersion();
433
434 if (article.getResourcePrimKey() <= 0) {
435 article =
436 JournalArticleLocalServiceUtil.checkArticleResourcePrimKey(
437 groupId, articleId, version);
438 }
439
440 ResourceLocalServiceUtil.addResources(
441 article.getCompanyId(), 0, 0, JournalArticle.class.getName(),
442 article.getResourcePrimKey(), false, false, false);
443
444 AssetEntry assetEntry = AssetEntryLocalServiceUtil.fetchEntry(
445 JournalArticle.class.getName(), article.getResourcePrimKey());
446
447 if (assetEntry == null) {
448 try {
449 JournalArticleLocalServiceUtil.updateAsset(
450 article.getUserId(), article, null, null, null);
451 }
452 catch (Exception e) {
453 if (_log.isWarnEnabled()) {
454 _log.warn(
455 "Unable to update asset for article " +
456 article.getId() + ": " + e.getMessage());
457 }
458 }
459 }
460 else if ((article.getStatus() ==
461 WorkflowConstants.STATUS_DRAFT) &&
462 (article.getVersion() ==
463 JournalArticleConstants.VERSION_DEFAULT)) {
464
465 AssetEntryLocalServiceUtil.updateEntry(
466 assetEntry.getClassName(), assetEntry.getClassPK(), null,
467 assetEntry.isVisible());
468 }
469
470 try {
471 JournalArticleLocalServiceUtil.checkStructure(
472 groupId, articleId, version);
473 }
474 catch (NoSuchStructureException nsse) {
475 if (_log.isWarnEnabled()) {
476 _log.warn(
477 "Removing reference to missing structure for article " +
478 article.getId());
479 }
480
481 article.setStructureId(StringPool.BLANK);
482 article.setTemplateId(StringPool.BLANK);
483
484 JournalArticleLocalServiceUtil.updateJournalArticle(article);
485 }
486 catch (Exception e) {
487 _log.error(
488 "Unable to check the structure for article " + article.getId(),
489 e);
490 }
491 }
492
493 protected void verifySearch() throws Exception {
494 Connection con = null;
495 PreparedStatement ps = null;
496 ResultSet rs = null;
497
498 try {
499 con = DataAccess.getUpgradeOptimizedConnection();
500
501 ps = con.prepareStatement(
502 "select groupId, portletId from JournalContentSearch group " +
503 "by groupId, portletId having count(groupId) > 1 and " +
504 "count(portletId) > 1");
505
506 rs = ps.executeQuery();
507
508 while (rs.next()) {
509 long groupId = rs.getLong("groupId");
510 String portletId = rs.getString("portletId");
511
512 verifyContentSearch(groupId, portletId);
513 }
514 }
515 finally {
516 DataAccess.cleanUp(con, ps, rs);
517 }
518 }
519
520 protected void verifyTree() throws Exception {
521 long[] companyIds = PortalInstances.getCompanyIdsBySQL();
522
523 for (long companyId : companyIds) {
524 JournalFolderLocalServiceUtil.rebuildTree(companyId);
525 }
526 }
527
528 protected void verifyURLTitle() throws Exception {
529 Connection con = null;
530 PreparedStatement ps = null;
531 ResultSet rs = null;
532
533 try {
534 con = DataAccess.getUpgradeOptimizedConnection();
535
536 ps = con.prepareStatement(
537 "select distinct groupId, articleId, urlTitle from " +
538 "JournalArticle");
539
540 rs = ps.executeQuery();
541
542 while (rs.next()) {
543 long groupId = rs.getLong("groupId");
544 String articleId = rs.getString("articleId");
545 String urlTitle = GetterUtil.getString(
546 rs.getString("urlTitle"));
547
548 updateURLTitle(groupId, articleId, urlTitle);
549 }
550 }
551 finally {
552 DataAccess.cleanUp(con, ps, rs);
553 }
554 }
555
556 private static Log _log = LogFactoryUtil.getLog(VerifyJournal.class);
557
558 private static Pattern _friendlyURLPattern = Pattern.compile("[^a-z0-9_-]");
559
560 }