1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.blogs.lar;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.util.GetterUtil;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.Validator;
32  import com.liferay.portal.kernel.xml.Document;
33  import com.liferay.portal.kernel.xml.DocumentException;
34  import com.liferay.portal.kernel.xml.Element;
35  import com.liferay.portal.kernel.xml.Namespace;
36  import com.liferay.portal.kernel.xml.Node;
37  import com.liferay.portal.kernel.xml.SAXReaderUtil;
38  import com.liferay.portal.lar.PortletDataContext;
39  import com.liferay.portal.model.User;
40  import com.liferay.portal.service.ServiceContext;
41  import com.liferay.portal.service.UserLocalServiceUtil;
42  import com.liferay.portal.service.persistence.UserUtil;
43  import com.liferay.portal.util.PortletKeys;
44  import com.liferay.portlet.blogs.model.BlogsEntry;
45  import com.liferay.portlet.blogs.service.BlogsEntryLocalServiceUtil;
46  import com.liferay.portlet.messageboards.model.MBMessage;
47  import com.liferay.portlet.messageboards.model.MBMessageDisplay;
48  import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
49  
50  import java.text.DateFormat;
51  import java.text.ParseException;
52  import java.text.SimpleDateFormat;
53  
54  import java.util.Calendar;
55  import java.util.Date;
56  import java.util.HashMap;
57  import java.util.List;
58  import java.util.Map;
59  import java.util.TimeZone;
60  
61  /**
62   * <a href="WordPressImporter.java.html"><b><i>View Source</i></b></a>
63   *
64   * @author Raymond Augé
65   *
66   */
67  public class WordPressImporter {
68  
69      public static void importData(PortletDataContext context)
70          throws PortalException, SystemException {
71  
72          Map<String, Long> userMap = getWordPressUserMap(context);
73  
74          String path = getWordPressPath(context, _EXPORT_FILE);
75  
76          String fileData = context.getZipEntryAsString(path);
77  
78          if (Validator.isNull(fileData)) {
79              return;
80          }
81  
82          Document wordPressDoc = null;
83  
84          try {
85              wordPressDoc = SAXReaderUtil.read(fileData);
86          }
87          catch (DocumentException de) {
88              _log.error("Reading " + path, de);
89  
90              return;
91          }
92  
93          User defaultUser = UserLocalServiceUtil.getDefaultUser(
94              context.getCompanyId());
95  
96          Element root = wordPressDoc.getRootElement();
97  
98          List<Element> entryEls = root.element("channel").elements("item");
99  
100         DateFormat dateFormat = new SimpleDateFormat(_DATE_FORMAT);
101 
102         dateFormat.setTimeZone(TimeZone.getTimeZone(StringPool.UTC));
103 
104         for (Element entryEl : entryEls) {
105             importEntry(context, defaultUser, userMap, dateFormat, entryEl);
106         }
107     }
108 
109     protected static String getWordPressPath(
110         PortletDataContext context, String fileName) {
111 
112         StringBuilder sb = new StringBuilder();
113 
114         sb.append(context.getSourcePortletPath(PortletKeys.BLOGS));
115         sb.append(StringPool.SLASH);
116         sb.append(fileName);
117 
118         return sb.toString();
119     }
120 
121     protected static Map<String, Long> getWordPressUserMap(
122         PortletDataContext context) {
123 
124         Map<String, Long> userMap = new HashMap<String, Long>();
125 
126         String path = getWordPressPath(context, _USER_MAP_FILE);
127 
128         String fileData = context.getZipEntryAsString(path);
129 
130         if (Validator.isNull(fileData)) {
131             return userMap;
132         }
133 
134         Document doc = null;
135 
136         try {
137             doc = SAXReaderUtil.read(fileData);
138         }
139         catch(DocumentException de) {
140             _log.error(de.getMessage(), de);
141 
142             return userMap;
143         }
144 
145         Element root = doc.getRootElement();
146 
147         List<Element> userEls = root.elements("wordpress-user");
148 
149         for (Element userEl : userEls) {
150             try {
151                 User user = UserUtil.findByC_EA(
152                     context.getCompanyId(),
153                     userEl.attributeValue("email-address"));
154 
155                 userMap.put(userEl.getTextTrim(), user.getUserId());
156             }
157             catch (Exception e) {
158                 if (_log.isDebugEnabled()) {
159                     _log.debug(
160                         "User for {" + context.getCompanyId() + ", " +
161                             userEl.attributeValue("email-address") + "}", e);
162                 }
163             }
164         }
165 
166         return userMap;
167     }
168 
169     protected static void importComment(
170             PortletDataContext context, User defaultUser,
171             MBMessageDisplay messageDisplay, Map<Long, Long> messageIdMap,
172             BlogsEntry entry, Element commentEl)
173         throws PortalException, SystemException {
174 
175         long commentId = GetterUtil.getLong(
176             commentEl.elementTextTrim(
177                 SAXReaderUtil.createQName("comment_id", _NS_WP)));
178 
179         String commentContent = commentEl.elementTextTrim(
180             SAXReaderUtil.createQName("comment_content", _NS_WP));
181 
182         if (Validator.isNull(commentContent)) {
183             return;
184         }
185 
186         String commentAuthor = commentEl.elementTextTrim(
187             SAXReaderUtil.createQName("comment_author", _NS_WP));
188 
189         commentAuthor = commentAuthor.substring(
190             0, Math.min(75, commentAuthor.length()));
191 
192         long commentParentId = GetterUtil.getLong(
193             commentEl.elementTextTrim(
194                 SAXReaderUtil.createQName("comment_parent", _NS_WP)));
195 
196         if (commentParentId == 0) {
197             commentParentId =
198                 messageDisplay.getMessage().getMessageId();
199         }
200         else {
201             commentParentId = messageIdMap.get(commentParentId);
202         }
203 
204         ServiceContext serviceContext = new ServiceContext();
205 
206         serviceContext.setAddCommunityPermissions(true);
207         serviceContext.setAddGuestPermissions(true);
208         serviceContext.setScopeGroupId(context.getGroupId());
209 
210         MBMessage message = MBMessageLocalServiceUtil.addDiscussionMessage(
211             defaultUser.getUserId(), commentAuthor, BlogsEntry.class.getName(),
212             entry.getEntryId(), messageDisplay.getThread().getThreadId(),
213             commentParentId, null, commentContent, serviceContext);
214 
215         messageIdMap.put(commentId, message.getMessageId());
216     }
217 
218     protected static void importEntry(
219             PortletDataContext context, User defaultUser,
220             Map<String, Long> userMap, DateFormat dateFormat, Element entryEl)
221         throws PortalException, SystemException {
222 
223         long userId = context.getUserId(null);
224 
225         String creator = entryEl.elementText(
226             SAXReaderUtil.createQName("creator", _NS_DC));
227 
228         if (userMap.containsKey(creator)) {
229             userId = userMap.get(creator);
230         }
231 
232         String title = entryEl.elementTextTrim("title");
233 
234         if (Validator.isNull(title)) {
235             title = entryEl.elementTextTrim(
236                 SAXReaderUtil.createQName("post_name", _NS_WP));
237         }
238 
239         String content = entryEl.elementText(
240             SAXReaderUtil.createQName("encoded", _NS_CONTENT));
241 
242         content = content.replaceAll("\\n", "\n<br />");
243 
244         // LPS-1425
245 
246         if (Validator.isNull(content)) {
247             content = "<br />";
248         }
249 
250         String dateText = entryEl.elementTextTrim(
251             SAXReaderUtil.createQName("post_date_gmt", _NS_WP));
252 
253         Date postDate = new Date();
254 
255         try {
256             postDate = dateFormat.parse(dateText);
257         }
258         catch (ParseException pe) {
259             _log.warn("Parse " + dateText, pe);
260         }
261 
262         Calendar cal = Calendar.getInstance();
263 
264         cal.setTime(postDate);
265 
266         int displayDateMonth = cal.get(Calendar.MONTH);
267         int displayDateDay = cal.get(Calendar.DAY_OF_MONTH);
268         int displayDateYear = cal.get(Calendar.YEAR);
269         int displayDateHour = cal.get(Calendar.HOUR_OF_DAY);
270         int displayDateMinute = cal.get(Calendar.MINUTE);
271 
272         String statusText = entryEl.elementTextTrim(
273             SAXReaderUtil.createQName("status", _NS_WP));
274 
275         boolean draft = statusText.equalsIgnoreCase("draft");
276 
277         String pingStatusText = entryEl.elementTextTrim(
278             SAXReaderUtil.createQName("ping_status", _NS_WP));
279 
280         boolean allowTrackbacks = pingStatusText.equalsIgnoreCase("open");
281 
282         String[] tagsEntries = null;
283 
284         String categoryText = entryEl.elementTextTrim("category");
285 
286         if (Validator.isNotNull(categoryText)) {
287             tagsEntries = new String[] {categoryText};
288         }
289 
290         ServiceContext serviceContext = new ServiceContext();
291 
292         serviceContext.setAddCommunityPermissions(true);
293         serviceContext.setAddGuestPermissions(true);
294         serviceContext.setScopeGroupId(context.getGroupId());
295         serviceContext.setTagsEntries(tagsEntries);
296 
297         BlogsEntry entry = null;
298 
299         try {
300             entry = BlogsEntryLocalServiceUtil.addEntry(
301                 userId, title, content, displayDateMonth, displayDateDay,
302                 displayDateYear, displayDateHour, displayDateMinute, draft,
303                 allowTrackbacks, null, serviceContext);
304         }
305         catch (Exception e) {
306             _log.error("Add entry " + title, e);
307 
308             return;
309         }
310 
311         MBMessageDisplay messageDisplay =
312             MBMessageLocalServiceUtil.getDiscussionMessageDisplay(
313                 userId, BlogsEntry.class.getName(), entry.getEntryId());
314 
315         Map<Long, Long> messageIdMap = new HashMap<Long, Long>();
316 
317         List<Node> commentNodes = entryEl.selectNodes(
318             "wp:comment", "wp:comment_parent/text()");
319 
320         for (Node commentNode : commentNodes) {
321             Element commentEl = (Element)commentNode;
322 
323             importComment(
324                 context, defaultUser, messageDisplay, messageIdMap, entry,
325                 commentEl);
326         }
327     }
328 
329     private static final String _DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
330 
331     private static final String _EXPORT_FILE = "wordpress.xml";
332 
333     private static final Namespace _NS_CONTENT = SAXReaderUtil.createNamespace(
334         "content", "http://purl.org/rss/1.0/modules/content/");
335 
336     private static final Namespace _NS_DC = SAXReaderUtil.createNamespace(
337         "dc", "http://purl.org/dc/elements/1.1/");
338 
339     private static final Namespace _NS_WP = SAXReaderUtil.createNamespace(
340         "wp", "http://wordpress.org/export/1.0/");
341 
342     private static final String _USER_MAP_FILE = "wordpress-user-map.xml";
343 
344     private static Log _log = LogFactoryUtil.getLog(WordPressImporter.class);
345 
346 }