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.language.LanguageUtil;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.upgrade.UpgradeProcess;
022    import com.liferay.portal.kernel.util.LocalizationUtil;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
027    import com.liferay.portal.kernel.xml.Document;
028    import com.liferay.portal.kernel.xml.Element;
029    import com.liferay.portal.kernel.xml.SAXReaderUtil;
030    import com.liferay.portal.util.PortalUtil;
031    import com.liferay.portlet.dynamicdatamapping.model.DDMContent;
032    import com.liferay.portlet.dynamicdatamapping.model.DDMStorageLink;
033    
034    import java.sql.Connection;
035    import java.sql.PreparedStatement;
036    import java.sql.ResultSet;
037    import java.sql.Timestamp;
038    
039    import java.util.HashMap;
040    import java.util.HashSet;
041    import java.util.Locale;
042    import java.util.Map;
043    import java.util.Set;
044    
045    /**
046     * @author Marcellus Tavares
047     */
048    public class UpgradeDynamicDataLists extends UpgradeProcess {
049    
050            protected void addDDMContent(
051                            String uuid_, long contentId, long groupId, long companyId,
052                            long userId, String userName, Timestamp createDate,
053                            Timestamp modifiedDate, String name, String description, String xml)
054                    throws Exception {
055    
056                    Connection con = null;
057                    PreparedStatement ps = null;
058    
059                    try {
060                            con = DataAccess.getUpgradeOptimizedConnection();
061    
062                            StringBundler sb = new StringBundler(4);
063    
064                            sb.append("insert into DDMContent (uuid_, contentId, groupId, ");
065                            sb.append("companyId, userId, userName, createDate, ");
066                            sb.append("modifiedDate, name, description, xml) values (?, ?, ");
067                            sb.append("?, ?, ?, ?, ?, ?, ?, ?, ?)");
068    
069                            String sql = sb.toString();
070    
071                            ps = con.prepareStatement(sql);
072    
073                            ps.setString(1, uuid_);
074                            ps.setLong(2, contentId);
075                            ps.setLong(3, groupId);
076                            ps.setLong(4, companyId);
077                            ps.setLong(5, userId);
078                            ps.setString(6, userName);
079                            ps.setTimestamp(7, createDate);
080                            ps.setTimestamp(8, modifiedDate);
081                            ps.setString(9, name);
082                            ps.setString(10, description);
083                            ps.setString(11, xml);
084    
085                            ps.executeUpdate();
086                    }
087                    catch (Exception e) {
088                            _log.error("Unable to add dynamic data mapping content ", e);
089    
090                            throw e;
091                    }
092                    finally {
093                            DataAccess.cleanUp(con, ps);
094                    }
095            }
096    
097            protected void addDynamicContentElements(
098                    Element dynamicElementElement, String name, String data) {
099    
100                    Map<Locale, String> localizationMap =
101                            LocalizationUtil.getLocalizationMap(data);
102    
103                    for (Map.Entry<Locale, String> entry : localizationMap.entrySet()) {
104                            String[] values = StringUtil.split(entry.getValue());
105    
106                            if (name.startsWith(StringPool.UNDERLINE)) {
107                                    values = new String[] {entry.getValue()};
108                            }
109    
110                            for (String value : values) {
111                                    Element dynamicContentElement =
112                                            dynamicElementElement.addElement("dynamic-content");
113    
114                                    dynamicContentElement.addAttribute(
115                                            "language-id", LanguageUtil.getLanguageId(entry.getKey()));
116                                    dynamicContentElement.addCDATA(value.trim());
117                            }
118                    }
119            }
120    
121            protected void deleteExpandoData(Set<Long> expandoRowIds) throws Exception {
122                    Connection con = null;
123                    PreparedStatement ps = null;
124                    ResultSet rs = null;
125    
126                    try {
127                            con = DataAccess.getUpgradeOptimizedConnection();
128    
129                            ps = con.prepareStatement(
130                                    "select tableId from ExpandoRow where " +
131                                            getExpandoRowIds(expandoRowIds) + " group by tableId");
132    
133                            int parameterIndex = 1;
134    
135                            for (long expandoRowId : expandoRowIds) {
136                                    ps.setLong(parameterIndex++, expandoRowId);
137                            }
138    
139                            rs = ps.executeQuery();
140    
141                            while (rs.next()) {
142                                    long tableId = rs.getLong("tableId");
143    
144                                    runSQL("delete from ExpandoTable where tableId = " + tableId);
145    
146                                    runSQL("delete from ExpandoRow where tableId = " + tableId);
147    
148                                    runSQL("delete from ExpandoColumn where tableId = " + tableId);
149    
150                                    runSQL("delete from ExpandoValue where tableId = " + tableId);
151                            }
152                    }
153                    finally {
154                            DataAccess.cleanUp(con, ps, rs);
155                    }
156            }
157    
158            @Override
159            protected void doUpgrade() throws Exception {
160                    setUpClassNameIds();
161    
162                    upgradeRecordVersions();
163            }
164    
165            protected String getExpandoRowIds(Set<Long> expandoRowIds) {
166                    StringBundler sb = new StringBundler((expandoRowIds.size() * 2) + 1);
167    
168                    sb.append(StringPool.OPEN_PARENTHESIS);
169    
170                    for (int i = 0; i < expandoRowIds.size(); i++) {
171                            sb.append("rowId_ = ?");
172    
173                            if ((i + 1) < expandoRowIds.size()) {
174                                    sb.append(" OR ");
175                            }
176                    }
177    
178                    sb.append(StringPool.CLOSE_PARENTHESIS);
179    
180                    return sb.toString();
181            }
182    
183            protected Map<String, String> getExpandoValuesMap(long expandoRowId)
184                    throws Exception {
185    
186                    Connection con = null;
187                    PreparedStatement ps = null;
188                    ResultSet rs = null;
189    
190                    try {
191                            con = DataAccess.getUpgradeOptimizedConnection();
192    
193                            StringBundler sb = new StringBundler(4);
194    
195                            sb.append("select ExpandoColumn.name, ExpandoValue.data_ from ");
196                            sb.append("ExpandoValue inner join ExpandoColumn on ");
197                            sb.append("ExpandoColumn.columnId = ExpandoValue.columnId where ");
198                            sb.append("rowId_ = ?");
199    
200                            ps = con.prepareStatement(sb.toString());
201    
202                            ps.setLong(1, expandoRowId);
203    
204                            rs = ps.executeQuery();
205    
206                            Map<String, String> fieldsMap = new HashMap<>();
207    
208                            while (rs.next()) {
209                                    String name = rs.getString("name");
210                                    String data_ = rs.getString("data_");
211    
212                                    fieldsMap.put(name, data_);
213                            }
214    
215                            return fieldsMap;
216                    }
217                    finally {
218                            DataAccess.cleanUp(con, ps, rs);
219                    }
220            }
221    
222            protected String getUpgradeRecordVersionsSQL() {
223                    StringBundler sb = new StringBundler(5);
224    
225                    sb.append("select DDLRecordVersion.* from DDLRecordVersion inner ");
226                    sb.append("join DDLRecordSet on DDLRecordVersion.recordSetId = ");
227                    sb.append("DDLRecordSet.recordSetId inner join DDMStructure on ");
228                    sb.append("DDLRecordSet.ddmStructureId = DDMStructure.structureId ");
229                    sb.append("where DDMStructure.storageType = 'expando'");
230    
231                    return sb.toString();
232            }
233    
234            protected void setUpClassNameIds() {
235                    _ddmContentClassNameId = PortalUtil.getClassNameId(DDMContent.class);
236    
237                    _expandoStorageAdapterClassNameId = PortalUtil.getClassNameId(
238                            "com.liferay.portlet.dynamicdatamapping.storage." +
239                                    "ExpandoStorageAdapter");
240            }
241    
242            protected String toXML(Map<String, String> expandoValuesMap) {
243                    Document document = SAXReaderUtil.createDocument();
244    
245                    Element rootElement = document.addElement("root");
246    
247                    for (Map.Entry<String, String> entry : expandoValuesMap.entrySet()) {
248                            Element dynamicElementElement = rootElement.addElement(
249                                    "dynamic-element");
250    
251                            String name = entry.getKey();
252                            String data = entry.getValue();
253    
254                            dynamicElementElement.addAttribute("name", name);
255                            dynamicElementElement.addAttribute(
256                                    "default-language-id",
257                                    LocalizationUtil.getDefaultLanguageId(data));
258    
259                            addDynamicContentElements(dynamicElementElement, name, data);
260                    }
261    
262                    return document.asXML();
263            }
264    
265            protected void updateDDMStorageLink(
266                            long oldClassNameId, long oldClassPK, long newClassNameId,
267                            long newClassPK)
268                    throws Exception {
269    
270                    runSQL(
271                            "update DDMStorageLink set classNameId = " + newClassNameId + ", " +
272                                    "classPK = " + newClassPK + " where classNameId = " +
273                                            oldClassNameId + " and classPK = " + oldClassPK);
274            }
275    
276            protected void updateDDMStructureStorageType() throws Exception {
277                    runSQL(
278                            "update DDMStructure set storageType = 'xml' where storageType = " +
279                                    "'expando'");
280            }
281    
282            protected void updateRecordDDMStorageId(
283                            long recordId, String version, long ddmContentId)
284                    throws Exception {
285    
286                    runSQL(
287                            "update DDLRecord set ddmStorageId = " + ddmContentId +
288                                    " where recordId = " + recordId + " and version = '" +
289                                            version + "'");
290            }
291    
292            protected void updateRecordVersionDDMStorageId(
293                            long recordVersionId, long DDMStorageId)
294                    throws Exception {
295    
296                    runSQL(
297                            "update DDLRecordVersion set ddmStorageId = " + DDMStorageId +
298                                    " where recordVersionId = " + recordVersionId);
299            }
300    
301            protected void upgradeRecordVersions() throws Exception {
302                    Connection con = null;
303                    PreparedStatement ps = null;
304                    ResultSet rs = null;
305    
306                    try {
307                            con = DataAccess.getUpgradeOptimizedConnection();
308    
309                            String sql = getUpgradeRecordVersionsSQL();
310    
311                            ps = con.prepareStatement(sql);
312    
313                            rs = ps.executeQuery();
314    
315                            Set<Long> ddmStorageIds = new HashSet<>();
316    
317                            while (rs.next()) {
318                                    long recordVersionId = rs.getLong("recordVersionId");
319                                    long groupId = rs.getLong("groupId");
320                                    long companyId = rs.getLong("companyId");
321                                    long userId = rs.getLong("userId");
322                                    String userName = rs.getString("userName");
323                                    Timestamp createDate = rs.getTimestamp("createDate");
324                                    long ddmStorageId = rs.getLong("DDMStorageId");
325                                    long recordId = rs.getLong("recordId");
326                                    String version = rs.getString("version");
327    
328                                    long ddmContentId = increment();
329    
330                                    Map<String, String> expandoValuesMap = getExpandoValuesMap(
331                                            ddmStorageId);
332    
333                                    String xml = toXML(expandoValuesMap);
334    
335                                    addDDMContent(
336                                            PortalUUIDUtil.generate(), ddmContentId, groupId, companyId,
337                                            userId, userName, createDate, createDate,
338                                            DDMStorageLink.class.getName(), null, xml);
339    
340                                    updateRecordVersionDDMStorageId(recordVersionId, ddmContentId);
341    
342                                    updateRecordDDMStorageId(recordId, version, ddmContentId);
343    
344                                    updateDDMStorageLink(
345                                            _expandoStorageAdapterClassNameId, ddmStorageId,
346                                            _ddmContentClassNameId, ddmContentId);
347    
348                                    ddmStorageIds.add(ddmStorageId);
349                            }
350    
351                            if (ddmStorageIds.isEmpty()) {
352                                    return;
353                            }
354    
355                            updateDDMStructureStorageType();
356    
357                            deleteExpandoData(ddmStorageIds);
358                    }
359                    finally {
360                            DataAccess.cleanUp(con, ps, rs);
361                    }
362            }
363    
364            private static final Log _log = LogFactoryUtil.getLog(
365                    UpgradeDynamicDataLists.class);
366    
367            private long _ddmContentClassNameId;
368            private long _expandoStorageAdapterClassNameId;
369    
370    }