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