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