001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.upgrade.v7_0_0;
016    
017    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.template.TemplateConstants;
021    import com.liferay.portal.kernel.upgrade.util.UpgradeProcessUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.LocaleUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
028    import com.liferay.portal.kernel.workflow.WorkflowConstants;
029    import com.liferay.portal.kernel.xml.Document;
030    import com.liferay.portal.kernel.xml.DocumentException;
031    import com.liferay.portal.kernel.xml.Element;
032    import com.liferay.portal.kernel.xml.SAXReaderUtil;
033    import com.liferay.portal.model.RoleConstants;
034    import com.liferay.portal.security.permission.ActionKeys;
035    import com.liferay.portal.upgrade.v7_0_0.util.JournalArticleTable;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portlet.dynamicdatamapping.io.DDMFormJSONDeserializerUtil;
038    import com.liferay.portlet.dynamicdatamapping.io.DDMFormXSDDeserializerUtil;
039    import com.liferay.portlet.dynamicdatamapping.model.DDMForm;
040    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
041    import com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants;
042    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
043    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplateConstants;
044    import com.liferay.portlet.dynamicdatamapping.storage.StorageType;
045    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
046    import com.liferay.portlet.journal.model.JournalArticle;
047    import com.liferay.util.ContentUtil;
048    
049    import java.sql.Connection;
050    import java.sql.PreparedStatement;
051    import java.sql.ResultSet;
052    import java.sql.SQLException;
053    import java.sql.Timestamp;
054    
055    import java.util.ArrayList;
056    import java.util.List;
057    import java.util.Locale;
058    import java.util.Map;
059    
060    /**
061     * @author Gergely Mathe
062     * @author Eudaldo Alonso
063     */
064    public class UpgradeJournal extends UpgradeBaseJournal {
065    
066            protected String addBasicWebContentStructureAndTemplate(long companyId)
067                    throws Exception {
068    
069                    long groupId = getCompanyGroupId(companyId);
070    
071                    String defaultLanguageId = UpgradeProcessUtil.getDefaultLanguageId(
072                            companyId);
073    
074                    Locale defaultLocale = LocaleUtil.fromLanguageId(defaultLanguageId);
075    
076                    List<Element> structureElements = getDDMStructures(defaultLocale);
077    
078                    Element structureElement = structureElements.get(0);
079    
080                    String name = structureElement.elementText("name");
081    
082                    String description = structureElement.elementText("description");
083    
084                    String localizedName = localize(groupId, name, defaultLanguageId);
085                    String localizedDescription = localize(
086                            groupId, description, defaultLanguageId);
087    
088                    Element structureElementRootElement = structureElement.element("root");
089    
090                    String xsd = structureElementRootElement.asXML();
091    
092                    if (hasDDMStructure(groupId, name) > 0) {
093                            return name;
094                    }
095    
096                    String ddmStructureUUID = PortalUUIDUtil.generate();
097    
098                    DDMForm ddmForm = DDMFormXSDDeserializerUtil.deserialize(xsd);
099    
100                    long ddmStructureId = addDDMStructure(
101                            ddmStructureUUID, increment(), groupId, companyId, name,
102                            localizedName, localizedDescription, toJSON(ddmForm),
103                            StorageType.JSON.toString());
104    
105                    String ddmTemplateUUID = PortalUUIDUtil.generate();
106    
107                    Element templateElement = structureElement.element("template");
108    
109                    String fileName = templateElement.elementText("file-name");
110                    boolean cacheable = GetterUtil.getBoolean(
111                            templateElement.elementText("cacheable"));
112    
113                    addDDMTemplate(
114                            ddmTemplateUUID, increment(), groupId, companyId, ddmStructureId,
115                            name, localizedName, localizedDescription, getContent(fileName),
116                            cacheable);
117    
118                    long stagingGroupId = getStagingGroupId(groupId);
119    
120                    if (stagingGroupId > 0) {
121                            ddmStructureId = addDDMStructure(
122                                    ddmStructureUUID, increment(), stagingGroupId, companyId, name,
123                                    localizedName, localizedDescription, toJSON(ddmForm),
124                                    StorageType.JSON.toString());
125    
126                            addDDMTemplate(
127                                    ddmTemplateUUID, increment(), stagingGroupId, companyId,
128                                    ddmStructureId, name, localizedName, localizedDescription,
129                                    getContent(fileName), cacheable);
130                    }
131    
132                    return name;
133            }
134    
135            protected long addDDMStructure(
136                            String uuid, long ddmStructureId, long groupId, long companyId,
137                            String ddmStructureKey, String localizedName,
138                            String localizedDescription, String definition, String storageType)
139                    throws Exception {
140    
141                    Timestamp now = new Timestamp(System.currentTimeMillis());
142    
143                    Connection con = null;
144                    PreparedStatement ps = null;
145    
146                    try {
147                            con = DataAccess.getUpgradeOptimizedConnection();
148    
149                            StringBundler sb = new StringBundler(6);
150    
151                            sb.append("insert into DDMStructure (uuid_, structureId, ");
152                            sb.append("groupId, companyId, userId, userName, createDate, ");
153                            sb.append("modifiedDate, parentStructureId, classNameId, ");
154                            sb.append("structureKey, version, name, description, definition, ");
155                            sb.append("storageType, type_) values (?, ?, ?, ?, ?, ?, ?, ?, ");
156                            sb.append("?, ?, ?, ?, ?, ?, ?, ?, ?)");
157    
158                            String sql = sb.toString();
159    
160                            ps = con.prepareStatement(sql);
161    
162                            ps.setString(1, uuid);
163                            ps.setLong(2, ddmStructureId);
164                            ps.setLong(3, groupId);
165                            ps.setLong(4, companyId);
166                            ps.setLong(5, getDefaultUserId(companyId));
167                            ps.setString(6, StringPool.BLANK);
168                            ps.setTimestamp(7, now);
169                            ps.setTimestamp(8, now);
170                            ps.setLong(9, DDMStructureConstants.DEFAULT_PARENT_STRUCTURE_ID);
171                            ps.setLong(10, PortalUtil.getClassNameId(JournalArticle.class));
172                            ps.setString(11, ddmStructureKey);
173                            ps.setString(12, DDMStructureConstants.VERSION_DEFAULT);
174                            ps.setString(13, localizedName);
175                            ps.setString(14, localizedDescription);
176                            ps.setString(15, definition);
177                            ps.setString(16, storageType);
178                            ps.setInt(17, DDMStructureConstants.TYPE_DEFAULT);
179    
180                            ps.executeUpdate();
181    
182                            long ddmStructureVersionId = increment();
183    
184                            addStructureVersion(
185                                    ddmStructureVersionId, groupId, companyId,
186                                    getDefaultUserId(companyId), StringPool.BLANK, now,
187                                    ddmStructureId,
188                                    DDMStructureConstants.DEFAULT_PARENT_STRUCTURE_ID,
189                                    localizedName, localizedDescription, definition, storageType,
190                                    DDMStructureConstants.TYPE_DEFAULT,
191                                    WorkflowConstants.STATUS_APPROVED, getDefaultUserId(companyId),
192                                    StringPool.BLANK, now);
193    
194                            String ddmStructureLayoutDefinition =
195                                    getDefaultDDMFormLayoutDefinition(definition);
196    
197                            addStructureLayout(
198                                    PortalUUIDUtil.generate(), increment(), groupId, companyId,
199                                    getDefaultUserId(companyId), StringPool.BLANK, now, now,
200                                    ddmStructureVersionId, ddmStructureLayoutDefinition);
201    
202                            Map<String, Long> bitwiseValues = getBitwiseValues(
203                                    DDMStructure.class.getName());
204    
205                            List<String> actionIds = new ArrayList<>();
206    
207                            actionIds.add(ActionKeys.VIEW);
208    
209                            long bitwiseValue = getBitwiseValue(bitwiseValues, actionIds);
210    
211                            addResourcePermission(
212                                    companyId, DDMStructure.class.getName(), ddmStructureId,
213                                    getRoleId(companyId, RoleConstants.GUEST), bitwiseValue);
214                            addResourcePermission(
215                                    companyId, DDMStructure.class.getName(), ddmStructureId,
216                                    getRoleId(companyId, RoleConstants.SITE_MEMBER), bitwiseValue);
217                    }
218                    catch (Exception e) {
219                            _log.error("Unable to create the basic web content structure");
220    
221                            throw e;
222                    }
223                    finally {
224                            DataAccess.cleanUp(con, ps);
225                    }
226    
227                    return ddmStructureId;
228            }
229    
230            protected long addDDMTemplate(
231                            String uuid, long ddmTemplateId, long groupId, long companyId,
232                            long ddmStructureId, String templateKey, String localizedName,
233                            String localizedDescription, String script, boolean cacheable)
234                    throws Exception {
235    
236                    Timestamp now = new Timestamp(System.currentTimeMillis());
237    
238                    Connection con = null;
239                    PreparedStatement ps = null;
240    
241                    try {
242                            con = DataAccess.getUpgradeOptimizedConnection();
243    
244                            StringBundler sb = new StringBundler(7);
245    
246                            sb.append("insert into DDMTemplate (uuid_, templateId, groupId, ");
247                            sb.append("companyId, userId, userName, createDate, modifiedDate,");
248                            sb.append("classNameId, classPK, templateKey, version, name, ");
249                            sb.append("description, type_, mode_, language, script, ");
250                            sb.append("cacheable, smallImage, smallImageId, smallImageURL) ");
251                            sb.append("values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ");
252                            sb.append("?, ?, ?, ?, ?, ?, ?)");
253    
254                            String sql = sb.toString();
255    
256                            ps = con.prepareStatement(sql);
257    
258                            ps.setString(1, uuid);
259                            ps.setLong(2, ddmTemplateId);
260                            ps.setLong(3, groupId);
261                            ps.setLong(4, companyId);
262                            ps.setLong(5, getDefaultUserId(companyId));
263                            ps.setString(6, StringPool.BLANK);
264                            ps.setTimestamp(7, now);
265                            ps.setTimestamp(8, now);
266                            ps.setLong(9, PortalUtil.getClassNameId(DDMStructure.class));
267                            ps.setLong(10, ddmStructureId);
268                            ps.setString(11, templateKey);
269                            ps.setString(12, DDMTemplateConstants.VERSION_DEFAULT);
270                            ps.setString(13, localizedName);
271                            ps.setString(14, localizedDescription);
272                            ps.setString(15, DDMTemplateConstants.TEMPLATE_TYPE_DISPLAY);
273                            ps.setString(16, DDMTemplateConstants.TEMPLATE_MODE_CREATE);
274                            ps.setString(17, TemplateConstants.LANG_TYPE_FTL);
275                            ps.setString(18, script);
276                            ps.setBoolean(19, cacheable);
277                            ps.setBoolean(20, false);
278                            ps.setLong(21, 0);
279                            ps.setString(22, StringPool.BLANK);
280    
281                            ps.executeUpdate();
282    
283                            addTemplateVersion(
284                                    increment(), groupId, companyId, getDefaultUserId(companyId),
285                                    StringPool.BLANK, now,
286                                    PortalUtil.getClassNameId(DDMStructure.class), ddmStructureId,
287                                    ddmTemplateId, localizedName, localizedDescription,
288                                    TemplateConstants.LANG_TYPE_FTL, script,
289                                    WorkflowConstants.STATUS_APPROVED, getDefaultUserId(companyId),
290                                    StringPool.BLANK, now);
291    
292                            Map<String, Long> bitwiseValues = getBitwiseValues(
293                                    DDMTemplate.class.getName());
294    
295                            List<String> actionIds = new ArrayList<>();
296    
297                            actionIds.add(ActionKeys.VIEW);
298    
299                            long bitwiseValue = getBitwiseValue(bitwiseValues, actionIds);
300    
301                            addResourcePermission(
302                                    companyId, DDMTemplate.class.getName(), ddmTemplateId,
303                                    getRoleId(companyId, RoleConstants.GUEST), bitwiseValue);
304                            addResourcePermission(
305                                    companyId, DDMTemplate.class.getName(), ddmTemplateId,
306                                    getRoleId(companyId, RoleConstants.SITE_MEMBER), bitwiseValue);
307                    }
308                    catch (Exception e) {
309                            _log.error("Unable to create the basic web content template");
310    
311                            throw e;
312                    }
313                    finally {
314                            DataAccess.cleanUp(con, ps);
315                    }
316    
317                    return ddmTemplateId;
318            }
319    
320            protected void addDDMTemplateLink(
321                            long classNameId, long classPK, long templateId)
322                    throws Exception {
323    
324                    Connection con = null;
325                    PreparedStatement ps = null;
326    
327                    try {
328                            con = DataAccess.getUpgradeOptimizedConnection();
329    
330                            ps = con.prepareStatement(
331                                    "insert into DDMTemplateLink (templateLinkId, classNameId, " +
332                                            "classPK, templateId) values (?, ?, ?, ?)");
333    
334                            ps.setLong(1, increment());
335                            ps.setLong(2, classNameId);
336                            ps.setLong(3, classPK);
337                            ps.setLong(4, templateId);
338    
339                            ps.executeUpdate();
340                    }
341                    catch (Exception e) {
342                            _log.error("Unable to create template link for journal article");
343    
344                            throw e;
345                    }
346                    finally {
347                            DataAccess.cleanUp(con, ps);
348                    }
349            }
350    
351            protected void addDDMTemplateLinks() throws Exception {
352                    long classNameId = PortalUtil.getClassNameId(DDMStructure.class);
353    
354                    Connection con = null;
355                    PreparedStatement ps = null;
356                    ResultSet rs = null;
357    
358                    try {
359                            con = DataAccess.getUpgradeOptimizedConnection();
360    
361                            StringBundler sb = new StringBundler(6);
362    
363                            sb.append("select DDMTemplate.templateId, JournalArticle.id_ ");
364                            sb.append("from JournalArticle inner join DDMTemplate on (");
365                            sb.append("DDMTemplate.groupId = JournalArticle.groupId and ");
366                            sb.append("DDMTemplate.templateKey = ");
367                            sb.append("JournalArticle.ddmTemplateKey and ");
368                            sb.append("JournalArticle.classNameId != ?)");
369    
370                            ps = con.prepareStatement(sb.toString());
371    
372                            ps.setLong(1, classNameId);
373    
374                            rs = ps.executeQuery();
375    
376                            while (rs.next()) {
377                                    long templateId = rs.getLong("templateId");
378                                    long id_ = rs.getLong("id_");
379    
380                                    addDDMTemplateLink(classNameId, id_, templateId);
381                            }
382                    }
383                    finally {
384                            DataAccess.cleanUp(con, ps, rs);
385                    }
386            }
387    
388            protected String convertStaticContentToDynamic(String content)
389                    throws Exception {
390    
391                    Document document = SAXReaderUtil.read(content);
392    
393                    Document newDocument = SAXReaderUtil.createDocument();
394    
395                    Element rootElement = document.getRootElement();
396    
397                    String availableLocales = rootElement.attributeValue(
398                            "available-locales");
399                    String defaultLocale = rootElement.attributeValue("default-locale");
400    
401                    Element newRootElement = SAXReaderUtil.createElement("root");
402    
403                    newRootElement.addAttribute("available-locales", availableLocales);
404                    newRootElement.addAttribute("default-locale", defaultLocale);
405    
406                    newDocument.add(newRootElement);
407    
408                    Element dynamicElementElement = SAXReaderUtil.createElement(
409                            "dynamic-element");
410    
411                    dynamicElementElement.addAttribute("name", "content");
412                    dynamicElementElement.addAttribute("type", "text_area");
413                    dynamicElementElement.addAttribute("index-type", "keyword");
414                    dynamicElementElement.addAttribute("index", String.valueOf(0));
415    
416                    newRootElement.add(dynamicElementElement);
417    
418                    List<Element> staticContentElements = rootElement.elements(
419                            "static-content");
420    
421                    for (Element staticContentElement : staticContentElements) {
422                            String languageId = staticContentElement.attributeValue(
423                                    "language-id");
424                            String text = staticContentElement.getText();
425    
426                            Element dynamicContentElement = SAXReaderUtil.createElement(
427                                    "dynamic-content");
428    
429                            dynamicContentElement.addAttribute("language-id", languageId);
430                            dynamicContentElement.addCDATA(text);
431    
432                            dynamicElementElement.add(dynamicContentElement);
433                    }
434    
435                    return DDMXMLUtil.formatXML(newDocument);
436            }
437    
438            @Override
439            protected void doUpgrade() throws Exception {
440                    try {
441                            runSQL(
442                                    "alter_column_name JournalArticle structureId " +
443                                            "DDMStructureKey VARCHAR(75) null");
444    
445                            runSQL(
446                                    "alter_column_name JournalArticle templateId DDMTemplateKey " +
447                                            "VARCHAR(75) null");
448    
449                            runSQL("alter_column_type JournalArticle description TEXT null");
450    
451                            runSQL(
452                                    "alter_column_name JournalFeed structureId DDMStructureKey " +
453                                            "TEXT null");
454    
455                            runSQL(
456                                    "alter_column_name JournalFeed templateId DDMTemplateKey " +
457                                            "TEXT null");
458    
459                            runSQL(
460                                    "alter_column_name JournalFeed rendererTemplateId " +
461                                            "DDMRendererTemplateKey TEXT null");
462                    }
463                    catch (SQLException sqle) {
464                            upgradeTable(
465                                    JournalArticleTable.TABLE_NAME,
466                                    JournalArticleTable.TABLE_COLUMNS,
467                                    JournalArticleTable.TABLE_SQL_CREATE,
468                                    JournalArticleTable.TABLE_SQL_ADD_INDEXES);
469                    }
470    
471                    updateBasicWebContentStructure();
472    
473                    addDDMTemplateLinks();
474            }
475    
476            protected String getContent(String fileName) {
477                    return ContentUtil.get(
478                            "com/liferay/portal/events/dependencies/" + fileName);
479            }
480    
481            protected List<Element> getDDMStructures(Locale locale)
482                    throws DocumentException {
483    
484                    String xml = getContent("basic-web-content-structure.xml");
485    
486                    xml = StringUtil.replace(xml, "[$LOCALE_DEFAULT$]", locale.toString());
487    
488                    Document document = SAXReaderUtil.read(xml);
489    
490                    Element rootElement = document.getRootElement();
491    
492                    return rootElement.elements("structure");
493            }
494    
495            protected String getDefaultDDMFormLayoutDefinition(String definition)
496                    throws Exception {
497    
498                    DDMForm ddmForm = DDMFormJSONDeserializerUtil.deserialize(definition);
499    
500                    return getDefaultDDMFormLayoutDefinition(ddmForm);
501            }
502    
503            protected long getStagingGroupId(long groupId) throws Exception {
504                    Connection con = null;
505                    PreparedStatement ps = null;
506                    ResultSet rs = null;
507    
508                    try {
509                            con = DataAccess.getUpgradeOptimizedConnection();
510    
511                            ps = con.prepareStatement(
512                                    "select groupId from Group_ where liveGroupId = ?");
513    
514                            ps.setLong(1, groupId);
515    
516                            rs = ps.executeQuery();
517    
518                            if (rs.next()) {
519                                    return rs.getLong("groupId");
520                            }
521    
522                            return 0;
523                    }
524                    finally {
525                            DataAccess.cleanUp(con, ps, rs);
526                    }
527            }
528    
529            protected int hasDDMStructure(long groupId, String ddmStructureKey)
530                    throws Exception {
531    
532                    Connection con = null;
533                    PreparedStatement ps = null;
534                    ResultSet rs = null;
535    
536                    try {
537                            con = DataAccess.getUpgradeOptimizedConnection();
538    
539                            ps = con.prepareStatement(
540                                    "select count(*) from DDMStructure where groupId = ? and " +
541                                            "classNameId = ? and structureKey = ?");
542    
543                            ps.setLong(1, groupId);
544                            ps.setLong(
545                                    2, PortalUtil.getClassNameId(JournalArticle.class.getName()));
546                            ps.setString(3, ddmStructureKey);
547    
548                            rs = ps.executeQuery();
549    
550                            if (rs.next()) {
551                                    int count = rs.getInt(1);
552    
553                                    return count;
554                            }
555    
556                            return 0;
557                    }
558                    finally {
559                            DataAccess.cleanUp(con, ps, rs);
560                    }
561            }
562    
563            protected void updateBasicWebContentStructure() throws Exception {
564                    Connection con = null;
565                    PreparedStatement ps = null;
566                    ResultSet rs = null;
567    
568                    try {
569                            con = DataAccess.getUpgradeOptimizedConnection();
570    
571                            ps = con.prepareStatement("select companyId from Company");
572    
573                            rs = ps.executeQuery();
574    
575                            while (rs.next()) {
576                                    long companyId = rs.getLong("companyId");
577    
578                                    updateJournalArticles(companyId);
579                            }
580                    }
581                    finally {
582                            DataAccess.cleanUp(con, ps, rs);
583                    }
584            }
585    
586            protected void updateJournalArticle(
587                            long id_, String ddmStructureKey, String ddmTemplateKey,
588                            String content)
589                    throws Exception {
590    
591                    Connection con = null;
592                    PreparedStatement ps = null;
593    
594                    try {
595                            con = DataAccess.getUpgradeOptimizedConnection();
596    
597                            ps = con.prepareStatement(
598                                    "update JournalArticle set ddmStructureKey = ?, " +
599                                            "ddmTemplateKey = ?, content = ? where id_ = ?");
600    
601                            ps.setString(1, ddmStructureKey);
602                            ps.setString(2, ddmTemplateKey);
603                            ps.setString(3, convertStaticContentToDynamic(content));
604                            ps.setLong(4, id_);
605    
606                            ps.executeUpdate();
607                    }
608                    finally {
609                            DataAccess.cleanUp(con, ps);
610                    }
611            }
612    
613            protected void updateJournalArticles(long companyId) throws Exception {
614                    Connection con = null;
615                    PreparedStatement ps = null;
616                    ResultSet rs = null;
617    
618                    try {
619                            con = DataAccess.getUpgradeOptimizedConnection();
620    
621                            ps = con.prepareStatement(
622                                    "select id_, content from JournalArticle where companyId = " +
623                                            companyId + " and ddmStructureKey is null or " +
624                                                    "ddmStructureKey like ''");
625    
626                            String name = addBasicWebContentStructureAndTemplate(companyId);
627    
628                            rs = ps.executeQuery();
629    
630                            while (rs.next()) {
631                                    long id_ = rs.getLong("id_");
632                                    String content = rs.getString("content");
633    
634                                    updateJournalArticle(id_, name, name, content);
635                            }
636                    }
637                    finally {
638                            DataAccess.cleanUp(con, ps, rs);
639                    }
640            }
641    
642            private static final Log _log = LogFactoryUtil.getLog(UpgradeJournal.class);
643    
644    }