001
014
015 package com.liferay.portlet.blogs.util;
016
017 import com.liferay.portal.kernel.language.LanguageUtil;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
021 import com.liferay.portal.kernel.portlet.FriendlyURLMapperThreadLocal;
022 import com.liferay.portal.kernel.util.ArrayUtil;
023 import com.liferay.portal.kernel.util.GetterUtil;
024 import com.liferay.portal.kernel.util.HttpUtil;
025 import com.liferay.portal.kernel.util.LocaleUtil;
026 import com.liferay.portal.kernel.util.StringBundler;
027 import com.liferay.portal.kernel.util.StringPool;
028 import com.liferay.portal.kernel.util.StringUtil;
029 import com.liferay.portal.kernel.util.Validator;
030 import com.liferay.portal.kernel.workflow.WorkflowConstants;
031 import com.liferay.portal.kernel.xmlrpc.Method;
032 import com.liferay.portal.kernel.xmlrpc.Response;
033 import com.liferay.portal.kernel.xmlrpc.XmlRpcConstants;
034 import com.liferay.portal.kernel.xmlrpc.XmlRpcUtil;
035 import com.liferay.portal.model.Portlet;
036 import com.liferay.portal.service.PortletLocalServiceUtil;
037 import com.liferay.portal.service.ServiceContext;
038 import com.liferay.portal.service.UserLocalServiceUtil;
039 import com.liferay.portal.util.Portal;
040 import com.liferay.portal.util.PortalUtil;
041 import com.liferay.portal.util.PortletKeys;
042 import com.liferay.portal.util.PropsValues;
043 import com.liferay.portlet.blogs.model.BlogsEntry;
044 import com.liferay.portlet.blogs.service.BlogsEntryLocalServiceUtil;
045 import com.liferay.portlet.messageboards.model.MBMessage;
046 import com.liferay.portlet.messageboards.model.MBMessageDisplay;
047 import com.liferay.portlet.messageboards.model.MBThread;
048 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
049
050 import java.io.IOException;
051
052 import java.net.URL;
053
054 import java.util.HashMap;
055 import java.util.List;
056 import java.util.Map;
057
058 import net.htmlparser.jericho.Element;
059 import net.htmlparser.jericho.Source;
060 import net.htmlparser.jericho.StartTag;
061 import net.htmlparser.jericho.TextExtractor;
062
063
066 public class PingbackMethodImpl implements Method {
067
068 public static final int ACCESS_DENIED = 49;
069
070 public static final int GENERIC_FAULT = 0;
071
072 public static final int PINGBACK_ALREADY_REGISTERED = 48;
073
074 public static final int SERVER_ERROR = 50;
075
076 public static final int SOURCE_URI_DOES_NOT_EXIST = 16;
077
078 public static final int SOURCE_URI_INVALID = 17;
079
080 public static final int TARGET_URI_DOES_NOT_EXIST = 32;
081
082 public static final int TARGET_URI_INVALID = 33;
083
084 @Override
085 public Response execute(long companyId) {
086 if (!PropsValues.BLOGS_PINGBACK_ENABLED) {
087 return XmlRpcUtil.createFault(
088 XmlRpcConstants.REQUESTED_METHOD_NOT_FOUND,
089 "Pingbacks are disabled");
090 }
091
092 Response response = validateSource();
093
094 if (response != null) {
095 return response;
096 }
097
098 try {
099 BlogsEntry entry = getBlogsEntry(companyId);
100
101 if (!entry.isAllowPingbacks()) {
102 return XmlRpcUtil.createFault(
103 XmlRpcConstants.REQUESTED_METHOD_NOT_FOUND,
104 "Pingbacks are disabled");
105 }
106
107 long userId = UserLocalServiceUtil.getDefaultUserId(companyId);
108 long groupId = entry.getGroupId();
109 String className = BlogsEntry.class.getName();
110 long classPK = entry.getEntryId();
111
112 MBMessageDisplay messageDisplay =
113 MBMessageLocalServiceUtil.getDiscussionMessageDisplay(
114 userId, groupId, className, classPK,
115 WorkflowConstants.STATUS_APPROVED);
116
117 MBThread thread = messageDisplay.getThread();
118
119 long threadId = thread.getThreadId();
120 long parentMessageId = thread.getRootMessageId();
121 String body =
122 "[...] " + getExcerpt() + " [...] [url=" + _sourceUri + "]" +
123 LanguageUtil.get(LocaleUtil.getSiteDefault(), "read-more") +
124 "[/url]";
125
126 List<MBMessage> messages =
127 MBMessageLocalServiceUtil.getThreadMessages(
128 threadId, WorkflowConstants.STATUS_APPROVED);
129
130 for (MBMessage message : messages) {
131 if (message.getBody().equals(body)) {
132 return XmlRpcUtil.createFault(
133 PINGBACK_ALREADY_REGISTERED,
134 "Pingback previously registered");
135 }
136 }
137
138 ServiceContext serviceContext = new ServiceContext();
139
140 String pingbackUserName = LanguageUtil.get(
141 LocaleUtil.getSiteDefault(), "pingback");
142
143 serviceContext.setAttribute("pingbackUserName", pingbackUserName);
144
145 StringBundler sb = new StringBundler(5);
146
147 String layoutFullURL = PortalUtil.getLayoutFullURL(
148 groupId, PortletKeys.BLOGS);
149
150 sb.append(layoutFullURL);
151
152 sb.append(Portal.FRIENDLY_URL_SEPARATOR);
153
154 Portlet portlet = PortletLocalServiceUtil.getPortletById(
155 companyId, PortletKeys.BLOGS);
156
157 sb.append(portlet.getFriendlyURLMapping());
158 sb.append(StringPool.SLASH);
159 sb.append(entry.getUrlTitle());
160
161 serviceContext.setAttribute("redirect", sb.toString());
162
163 serviceContext.setLayoutFullURL(layoutFullURL);
164
165 MBMessageLocalServiceUtil.addDiscussionMessage(
166 userId, StringPool.BLANK, groupId, className, classPK, threadId,
167 parentMessageId, StringPool.BLANK, body, serviceContext);
168
169 return XmlRpcUtil.createSuccess("Pingback accepted");
170 }
171 catch (Exception e) {
172 if (_log.isDebugEnabled()) {
173 _log.debug(e, e);
174 }
175
176 return XmlRpcUtil.createFault(
177 TARGET_URI_INVALID, "Error parsing target URI");
178 }
179 }
180
181 @Override
182 public String getMethodName() {
183 return "pingback.ping";
184 }
185
186 @Override
187 public String getToken() {
188 return "pingback";
189 }
190
191 @Override
192 public boolean setArguments(Object[] arguments) {
193 try {
194 _sourceUri = (String)arguments[0];
195 _targetUri = (String)arguments[1];
196
197 return true;
198 }
199 catch (Exception e) {
200 return false;
201 }
202 }
203
204 protected BlogsEntry getBlogsEntry(long companyId) throws Exception {
205 BlogsEntry entry = null;
206
207 URL url = new URL(_targetUri);
208
209 String friendlyURL = url.getPath();
210
211 int end = friendlyURL.indexOf(Portal.FRIENDLY_URL_SEPARATOR);
212
213 if (end != -1) {
214 friendlyURL = friendlyURL.substring(0, end);
215 }
216
217 long plid = PortalUtil.getPlidFromFriendlyURL(companyId, friendlyURL);
218 long groupId = PortalUtil.getScopeGroupId(plid);
219
220 Map<String, String[]> params = new HashMap<String, String[]>();
221
222 FriendlyURLMapperThreadLocal.setPRPIdentifiers(
223 new HashMap<String, String>());
224
225 Portlet portlet = PortletLocalServiceUtil.getPortletById(
226 PortletKeys.BLOGS);
227
228 FriendlyURLMapper friendlyURLMapper =
229 portlet.getFriendlyURLMapperInstance();
230
231 friendlyURL = url.getPath();
232
233 end = friendlyURL.indexOf(Portal.FRIENDLY_URL_SEPARATOR);
234
235 if (end != -1) {
236 friendlyURL = friendlyURL.substring(
237 end + Portal.FRIENDLY_URL_SEPARATOR.length() - 1);
238 }
239
240 Map<String, Object> requestContext = new HashMap<String, Object>();
241
242 friendlyURLMapper.populateParams(friendlyURL, params, requestContext);
243
244 String param = getParam(params, "entryId");
245
246 if (Validator.isNotNull(param)) {
247 long entryId = GetterUtil.getLong(param);
248
249 entry = BlogsEntryLocalServiceUtil.getEntry(entryId);
250 }
251 else {
252 String urlTitle = getParam(params, "urlTitle");
253
254 entry = BlogsEntryLocalServiceUtil.getEntry(groupId, urlTitle);
255 }
256
257 return entry;
258 }
259
260 protected String getExcerpt() throws IOException {
261 String html = HttpUtil.URLtoString(_sourceUri);
262
263 Source source = new Source(html);
264
265 source.fullSequentialParse();
266
267 List<Element> elements = source.getAllElements("a");
268
269 for (Element element : elements) {
270 String href = GetterUtil.getString(
271 element.getAttributeValue("href"));
272
273 if (href.equals(_targetUri)) {
274 element = element.getParentElement();
275
276 TextExtractor textExtractor = new TextExtractor(element);
277
278 String body = textExtractor.toString();
279
280 if (body.length() < PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH) {
281 element = element.getParentElement();
282
283 if (element != null) {
284 textExtractor = new TextExtractor(element);
285
286 body = textExtractor.toString();
287 }
288 }
289
290 return StringUtil.shorten(
291 body, PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH);
292 }
293 }
294
295 return StringPool.BLANK;
296 }
297
298 protected String getParam(Map<String, String[]> params, String name) {
299 String[] paramArray = params.get(name);
300
301 if (paramArray == null) {
302 String namespace = PortalUtil.getPortletNamespace(
303 PortletKeys.BLOGS);
304
305 paramArray = params.get(namespace + name);
306 }
307
308 if (ArrayUtil.isNotEmpty(paramArray)) {
309 return paramArray[0];
310 }
311 else {
312 return null;
313 }
314 }
315
316 protected Response validateSource() {
317 Source source = null;
318
319 try {
320 String html = HttpUtil.URLtoString(_sourceUri);
321
322 source = new Source(html);
323 }
324 catch (Exception e) {
325 return XmlRpcUtil.createFault(
326 SOURCE_URI_DOES_NOT_EXIST, "Error accessing source URI");
327 }
328
329 List<StartTag> startTags = source.getAllStartTags("a");
330
331 for (StartTag startTag : startTags) {
332 String href = GetterUtil.getString(
333 startTag.getAttributeValue("href"));
334
335 if (href.equals(_targetUri)) {
336 return null;
337 }
338 }
339
340 return XmlRpcUtil.createFault(
341 SOURCE_URI_INVALID, "Could not find target URI in source");
342 }
343
344 private static Log _log = LogFactoryUtil.getLog(PingbackMethodImpl.class);
345
346 private String _sourceUri;
347 private String _targetUri;
348
349 }