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