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 PortalException, 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.getArticleImage(articleImageId);
217
218 articleImage.setElName(name + StringPool.UNDERLINE + index);
219
220 JournalArticleImageLocalServiceUtil.updateJournalArticleImage(
221 articleImage);
222 }
223
224 protected void updateLinkToLayoutElements(long groupId, Element element) {
225 Element dynamicContentElement = element.element("dynamic-content");
226
227 Node node = dynamicContentElement.node(0);
228
229 String text = node.getText();
230
231 if (!text.isEmpty() && !text.endsWith(StringPool.AT + groupId)) {
232 node.setText(
233 dynamicContentElement.getStringValue() + StringPool.AT +
234 groupId);
235 }
236 }
237
238 protected void updateURLTitle(
239 long groupId, String articleId, String urlTitle)
240 throws Exception {
241
242 String normalizedURLTitle = FriendlyURLNormalizerUtil.normalize(
243 urlTitle, _friendlyURLPattern);
244
245 if (urlTitle.equals(normalizedURLTitle)) {
246 return;
247 }
248
249 normalizedURLTitle = JournalArticleLocalServiceUtil.getUniqueUrlTitle(
250 groupId, articleId, normalizedURLTitle);
251
252 Connection con = null;
253 PreparedStatement ps = null;
254
255 try {
256 con = DataAccess.getUpgradeOptimizedConnection();
257
258 ps = con.prepareStatement(
259 "update JournalArticle set urlTitle = ? where urlTitle = ?");
260
261 ps.setString(1, normalizedURLTitle);
262 ps.setString(2, urlTitle);
263
264 ps.executeUpdate();
265 }
266 finally {
267 DataAccess.cleanUp(con, ps);
268 }
269 }
270
271 protected void verifyContent() throws Exception {
272 Connection con = null;
273 PreparedStatement ps = null;
274 ResultSet rs = null;
275
276 try {
277 con = DataAccess.getUpgradeOptimizedConnection();
278
279 ps = con.prepareStatement(
280 "select id_ from JournalArticle where (content like " +
281 "'%document_library%' or content like '%link_to_layout%')" +
282 " and structureId != ''");
283
284 rs = ps.executeQuery();
285
286 while (rs.next()) {
287 long id = rs.getLong("id_");
288
289 JournalArticle article =
290 JournalArticleLocalServiceUtil.getArticle(id);
291
292 Document document = SAXReaderUtil.read(article.getContent());
293
294 Element rootElement = document.getRootElement();
295
296 for (Element element : rootElement.elements()) {
297 updateElement(article.getGroupId(), element);
298 }
299
300 article.setContent(document.asXML());
301
302 JournalArticleLocalServiceUtil.updateJournalArticle(article);
303 }
304 }
305 finally {
306 DataAccess.cleanUp(con, ps, rs);
307 }
308 }
309
310 protected void verifyContentSearch(long groupId, String portletId)
311 throws Exception {
312
313 Connection con = null;
314 PreparedStatement ps = null;
315 ResultSet rs = null;
316
317 try {
318 con = DataAccess.getUpgradeOptimizedConnection();
319
320 ps = con.prepareStatement(
321 "select preferences from PortletPreferences inner join " +
322 "Layout on PortletPreferences.plid = Layout.plid where " +
323 "groupId = ? and portletId = ?");
324
325 ps.setLong(1, groupId);
326 ps.setString(2, portletId);
327
328 rs = ps.executeQuery();
329
330 while (rs.next()) {
331 String xml = rs.getString("preferences");
332
333 PortletPreferences portletPreferences =
334 PortletPreferencesFactoryUtil.fromDefaultXML(xml);
335
336 String articleId = portletPreferences.getValue(
337 "articleId", null);
338
339 List<JournalContentSearch> contentSearches =
340 JournalContentSearchLocalServiceUtil.
341 getArticleContentSearches(groupId, articleId);
342
343 if (contentSearches.isEmpty()) {
344 continue;
345 }
346
347 JournalContentSearch contentSearch = contentSearches.get(0);
348
349 JournalContentSearchLocalServiceUtil.updateContentSearch(
350 contentSearch.getGroupId(), contentSearch.isPrivateLayout(),
351 contentSearch.getLayoutId(), contentSearch.getPortletId(),
352 articleId, true);
353 }
354 }
355 finally {
356 DataAccess.cleanUp(con, ps, rs);
357 }
358 }
359
360 protected void verifyDynamicElements()
361 throws PortalException, SystemException {
362
363 ActionableDynamicQuery actionableDynamicQuery =
364 new JournalArticleActionableDynamicQuery() {
365
366 @Override
367 public void performAction(Object object) {
368 JournalArticle article = (JournalArticle)object;
369
370 try {
371 verifyDynamicElements(article);
372 }
373 catch (Exception e) {
374 _log.error(
375 "Unable to update content for article " +
376 article.getId(),
377 e);
378 }
379 }
380
381 };
382
383 actionableDynamicQuery.performActions();
384
385 if (_log.isDebugEnabled()) {
386 _log.debug("Dynamic elements verified for articles");
387 }
388 }
389
390 protected void verifyDynamicElements(JournalArticle article)
391 throws Exception {
392
393 Document document = SAXReaderUtil.read(article.getContent());
394
395 Element rootElement = document.getRootElement();
396
397 updateDynamicElements(rootElement.elements("dynamic-element"));
398
399 article.setContent(document.asXML());
400
401 JournalArticleLocalServiceUtil.updateJournalArticle(article);
402 }
403
404 protected void verifyOracleNewLine() throws Exception {
405 DB db = DBFactoryUtil.getDB();
406
407 String dbType = db.getType();
408
409 if (!dbType.equals(DB.TYPE_ORACLE)) {
410 return;
411 }
412
413
414
415
416
417
418
419 boolean checkNewLine = false;
420
421 List<JournalArticle> articles =
422 JournalArticleLocalServiceUtil.getArticles(
423 DEFAULT_GROUP_ID, 0, NUM_OF_ARTICLES);
424
425 for (JournalArticle article : articles) {
426 String content = article.getContent();
427
428 if ((content != null) && content.contains("\\n")) {
429 articles = JournalArticleLocalServiceUtil.getArticles(
430 DEFAULT_GROUP_ID);
431
432 for (int j = 0; j < articles.size(); j++) {
433 article = articles.get(j);
434
435 JournalArticleLocalServiceUtil.checkNewLine(
436 article.getGroupId(), article.getArticleId(),
437 article.getVersion());
438 }
439
440 checkNewLine = true;
441
442 break;
443 }
444 }
445
446
447
448 if (!checkNewLine) {
449 if (_log.isInfoEnabled()) {
450 _log.info("Do not fix oracle new line");
451 }
452
453 return;
454 }
455 else {
456 if (_log.isInfoEnabled()) {
457 _log.info("Fix oracle new line");
458 }
459 }
460 }
461
462 protected void verifyPermissionsAndAssets() throws Exception {
463 ActionableDynamicQuery actionableDynamicQuery =
464 new JournalArticleActionableDynamicQuery() {
465
466 @Override
467 protected void performAction(Object object)
468 throws PortalException, SystemException {
469
470 JournalArticle article = (JournalArticle)object;
471
472 long groupId = article.getGroupId();
473 String articleId = article.getArticleId();
474 double version = article.getVersion();
475 String structureId = article.getStructureId();
476
477 if (article.getResourcePrimKey() <= 0) {
478 article =
479 JournalArticleLocalServiceUtil.
480 checkArticleResourcePrimKey(
481 groupId, articleId, version);
482 }
483
484 ResourceLocalServiceUtil.addResources(
485 article.getCompanyId(), 0, 0,
486 JournalArticle.class.getName(),
487 article.getResourcePrimKey(), false, false, false);
488
489 AssetEntry assetEntry = AssetEntryLocalServiceUtil.fetchEntry(
490 JournalArticle.class.getName(),
491 article.getResourcePrimKey());
492
493 if (assetEntry == null) {
494 try {
495 JournalArticleLocalServiceUtil.updateAsset(
496 article.getUserId(), article, null, null, null);
497 }
498 catch (Exception e) {
499 if (_log.isWarnEnabled()) {
500 _log.warn(
501 "Unable to update asset for article " +
502 article.getId() + ": " + e.getMessage());
503 }
504 }
505 }
506 else if ((article.getStatus() ==
507 WorkflowConstants.STATUS_DRAFT) &&
508 (article.getVersion() ==
509 JournalArticleConstants.VERSION_DEFAULT)) {
510
511 AssetEntryLocalServiceUtil.updateEntry(
512 assetEntry.getClassName(), assetEntry.getClassPK(),
513 null, assetEntry.isVisible());
514 }
515
516 if (Validator.isNotNull(structureId)) {
517
523 }
524
525 try {
526 JournalArticleLocalServiceUtil.checkStructure(
527 groupId, articleId, version);
528 }
529 catch (NoSuchStructureException nsse) {
530 if (_log.isWarnEnabled()) {
531 _log.warn(
532 "Removing reference to missing structure for " +
533 "article " + article.getId());
534 }
535
536 article.setStructureId(StringPool.BLANK);
537 article.setTemplateId(StringPool.BLANK);
538
539 JournalArticleLocalServiceUtil.updateJournalArticle(
540 article);
541 }
542 }
543
544 };
545
546 actionableDynamicQuery.performActions();
547
548 if (_log.isDebugEnabled()) {
549 _log.debug("Permissions and assets verified for articles");
550 }
551 }
552
553 protected void verifySearch() throws Exception {
554 Connection con = null;
555 PreparedStatement ps = null;
556 ResultSet rs = null;
557
558 try {
559 con = DataAccess.getUpgradeOptimizedConnection();
560
561 ps = con.prepareStatement(
562 "select groupId, portletId from JournalContentSearch group " +
563 "by groupId, portletId having count(groupId) > 1 and " +
564 "count(portletId) > 1");
565
566 rs = ps.executeQuery();
567
568 while (rs.next()) {
569 long groupId = rs.getLong("groupId");
570 String portletId = rs.getString("portletId");
571
572 verifyContentSearch(groupId, portletId);
573 }
574 }
575 finally {
576 DataAccess.cleanUp(con, ps, rs);
577 }
578 }
579
580 protected void verifyTree() throws Exception {
581 long[] companyIds = PortalInstances.getCompanyIdsBySQL();
582
583 for (long companyId : companyIds) {
584 JournalArticleLocalServiceUtil.rebuildTree(companyId);
585 JournalFolderLocalServiceUtil.rebuildTree(companyId);
586 }
587 }
588
589 protected void verifyURLTitle() throws Exception {
590 Connection con = null;
591 PreparedStatement ps = null;
592 ResultSet rs = null;
593
594 try {
595 con = DataAccess.getUpgradeOptimizedConnection();
596
597 ps = con.prepareStatement(
598 "select distinct groupId, articleId, urlTitle from " +
599 "JournalArticle");
600
601 rs = ps.executeQuery();
602
603 while (rs.next()) {
604 long groupId = rs.getLong("groupId");
605 String articleId = rs.getString("articleId");
606 String urlTitle = GetterUtil.getString(
607 rs.getString("urlTitle"));
608
609 updateURLTitle(groupId, articleId, urlTitle);
610 }
611 }
612 finally {
613 DataAccess.cleanUp(con, ps, rs);
614 }
615 }
616
617 private static Log _log = LogFactoryUtil.getLog(VerifyJournal.class);
618
619 private static Pattern _friendlyURLPattern = Pattern.compile("[^a-z0-9_-]");
620
621 }