001
014
015 package com.liferay.portlet.blogs.util;
016
017 import com.liferay.portal.kernel.comment.CommentManager;
018 import com.liferay.portal.kernel.comment.DuplicateCommentException;
019 import com.liferay.portal.kernel.language.LanguageUtil;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
023 import com.liferay.portal.kernel.portlet.FriendlyURLMapperThreadLocal;
024 import com.liferay.portal.kernel.util.ArrayUtil;
025 import com.liferay.portal.kernel.util.GetterUtil;
026 import com.liferay.portal.kernel.util.HttpUtil;
027 import com.liferay.portal.kernel.util.LocaleUtil;
028 import com.liferay.portal.kernel.util.StringBundler;
029 import com.liferay.portal.kernel.util.StringPool;
030 import com.liferay.portal.kernel.util.StringUtil;
031 import com.liferay.portal.kernel.util.Validator;
032 import com.liferay.portal.kernel.xmlrpc.Method;
033 import com.liferay.portal.kernel.xmlrpc.Response;
034 import com.liferay.portal.kernel.xmlrpc.XmlRpcConstants;
035 import com.liferay.portal.kernel.xmlrpc.XmlRpcUtil;
036 import com.liferay.portal.model.Portlet;
037 import com.liferay.portal.service.PortletLocalServiceUtil;
038 import com.liferay.portal.service.ServiceContext;
039 import com.liferay.portal.service.UserLocalServiceUtil;
040 import com.liferay.portal.util.Portal;
041 import com.liferay.portal.util.PortalUtil;
042 import com.liferay.portal.util.PortletKeys;
043 import com.liferay.portal.util.PropsValues;
044 import com.liferay.portlet.blogs.model.BlogsEntry;
045 import com.liferay.portlet.blogs.pingback.DisabledPingbackException;
046 import com.liferay.portlet.blogs.pingback.InvalidSourceURIException;
047 import com.liferay.portlet.blogs.pingback.UnavailableSourceURIException;
048 import com.liferay.portlet.blogs.service.BlogsEntryLocalServiceUtil;
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 try {
087 addPingback(companyId);
088
089 return XmlRpcUtil.createSuccess("Pingback accepted");
090 }
091 catch (DuplicateCommentException dce) {
092 return XmlRpcUtil.createFault(
093 PINGBACK_ALREADY_REGISTERED, "Pingback is already registered");
094 }
095 catch (InvalidSourceURIException isue) {
096 return XmlRpcUtil.createFault(
097 SOURCE_URI_INVALID, isue.getMessage());
098 }
099 catch (DisabledPingbackException pde) {
100 return XmlRpcUtil.createFault(
101 XmlRpcConstants.REQUESTED_METHOD_NOT_FOUND, pde.getMessage());
102 }
103 catch (UnavailableSourceURIException usue) {
104 return XmlRpcUtil.createFault(
105 SOURCE_URI_DOES_NOT_EXIST, usue.getMessage());
106 }
107 catch (Exception e) {
108 if (_log.isDebugEnabled()) {
109 _log.debug(e, e);
110 }
111
112 return XmlRpcUtil.createFault(
113 TARGET_URI_INVALID, "Unable to parse target URI");
114 }
115 }
116
117 @Override
118 public String getMethodName() {
119 return "pingback.ping";
120 }
121
122 @Override
123 public String getToken() {
124 return "pingback";
125 }
126
127 @Override
128 public boolean setArguments(Object[] arguments) {
129 try {
130 _sourceURI = (String)arguments[0];
131 _targetURI = (String)arguments[1];
132
133 return true;
134 }
135 catch (Exception e) {
136 if (_log.isDebugEnabled()) {
137 _log.debug(e, e);
138 }
139
140 return false;
141 }
142 }
143
144 public void setCommentManager(CommentManager commentManager) {
145 _commentManager = commentManager;
146 }
147
148 protected void addPingback(long companyId) throws Exception {
149 if (!PropsValues.BLOGS_PINGBACK_ENABLED) {
150 throw new DisabledPingbackException("Pingbacks are disabled");
151 }
152
153 validateSource();
154
155 BlogsEntry entry = getBlogsEntry(companyId);
156
157 if (!entry.isAllowPingbacks()) {
158 throw new DisabledPingbackException("Pingbacks are disabled");
159 }
160
161 long userId = UserLocalServiceUtil.getDefaultUserId(companyId);
162 long groupId = entry.getGroupId();
163 String className = BlogsEntry.class.getName();
164 long classPK = entry.getEntryId();
165
166 String body =
167 "[...] " + getExcerpt() + " [...] [url=" + _sourceURI + "]" +
168 LanguageUtil.get(LocaleUtil.getSiteDefault(), "read-more") +
169 "[/url]";
170
171 ServiceContext serviceContext = buildServiceContext(
172 companyId, groupId, entry.getUrlTitle());
173
174 _commentManager.addComment(
175 userId, groupId, className, classPK, body, serviceContext);
176 }
177
178 protected ServiceContext buildServiceContext(
179 long companyId, long groupId, String urlTitle)
180 throws Exception {
181
182 ServiceContext serviceContext = new ServiceContext();
183
184 String pingbackUserName = LanguageUtil.get(
185 LocaleUtil.getSiteDefault(), "pingback");
186
187 serviceContext.setAttribute("pingbackUserName", pingbackUserName);
188
189 StringBundler sb = new StringBundler(5);
190
191 String layoutFullURL = PortalUtil.getLayoutFullURL(
192 groupId, PortletKeys.BLOGS);
193
194 sb.append(layoutFullURL);
195
196 sb.append(Portal.FRIENDLY_URL_SEPARATOR);
197
198 Portlet portlet = PortletLocalServiceUtil.getPortletById(
199 companyId, PortletKeys.BLOGS);
200
201 sb.append(portlet.getFriendlyURLMapping());
202 sb.append(StringPool.SLASH);
203 sb.append(urlTitle);
204
205 serviceContext.setAttribute("redirect", sb.toString());
206
207 serviceContext.setLayoutFullURL(layoutFullURL);
208
209 return serviceContext;
210 }
211
212 protected BlogsEntry getBlogsEntry(long companyId) throws Exception {
213 BlogsEntry entry = null;
214
215 URL url = new URL(_targetURI);
216
217 String friendlyURL = url.getPath();
218
219 int end = friendlyURL.indexOf(Portal.FRIENDLY_URL_SEPARATOR);
220
221 if (end != -1) {
222 friendlyURL = friendlyURL.substring(0, end);
223 }
224
225 long plid = PortalUtil.getPlidFromFriendlyURL(companyId, friendlyURL);
226 long groupId = PortalUtil.getScopeGroupId(plid);
227
228 Map<String, String[]> params = new HashMap<String, String[]>();
229
230 FriendlyURLMapperThreadLocal.setPRPIdentifiers(
231 new HashMap<String, String>());
232
233 Portlet portlet = PortletLocalServiceUtil.getPortletById(
234 PortletKeys.BLOGS);
235
236 FriendlyURLMapper friendlyURLMapper =
237 portlet.getFriendlyURLMapperInstance();
238
239 friendlyURL = url.getPath();
240
241 end = friendlyURL.indexOf(Portal.FRIENDLY_URL_SEPARATOR);
242
243 if (end != -1) {
244 friendlyURL = friendlyURL.substring(
245 end + Portal.FRIENDLY_URL_SEPARATOR.length() - 1);
246 }
247
248 Map<String, Object> requestContext = new HashMap<String, Object>();
249
250 friendlyURLMapper.populateParams(friendlyURL, params, requestContext);
251
252 String param = getParam(params, "entryId");
253
254 if (Validator.isNotNull(param)) {
255 long entryId = GetterUtil.getLong(param);
256
257 entry = BlogsEntryLocalServiceUtil.getEntry(entryId);
258 }
259 else {
260 String urlTitle = getParam(params, "urlTitle");
261
262 entry = BlogsEntryLocalServiceUtil.getEntry(groupId, urlTitle);
263 }
264
265 return entry;
266 }
267
268 protected String getExcerpt() throws IOException {
269 String html = HttpUtil.URLtoString(_sourceURI);
270
271 Source source = new Source(html);
272
273 source.fullSequentialParse();
274
275 List<Element> elements = source.getAllElements("a");
276
277 for (Element element : elements) {
278 String href = GetterUtil.getString(
279 element.getAttributeValue("href"));
280
281 if (href.equals(_targetURI)) {
282 element = element.getParentElement();
283
284 TextExtractor textExtractor = new TextExtractor(element);
285
286 String body = textExtractor.toString();
287
288 if (body.length() < PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH) {
289 element = element.getParentElement();
290
291 if (element != null) {
292 textExtractor = new TextExtractor(element);
293
294 body = textExtractor.toString();
295 }
296 }
297
298 return StringUtil.shorten(
299 body, PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH);
300 }
301 }
302
303 return StringPool.BLANK;
304 }
305
306 protected String getParam(Map<String, String[]> params, String name) {
307 String[] paramArray = params.get(name);
308
309 if (paramArray == null) {
310 String namespace = PortalUtil.getPortletNamespace(
311 PortletKeys.BLOGS);
312
313 paramArray = params.get(namespace + name);
314 }
315
316 if (ArrayUtil.isNotEmpty(paramArray)) {
317 return paramArray[0];
318 }
319 else {
320 return null;
321 }
322 }
323
324 protected void validateSource() throws Exception {
325 Source source = null;
326
327 try {
328 String html = HttpUtil.URLtoString(_sourceURI);
329
330 source = new Source(html);
331 }
332 catch (Exception e) {
333 if (_log.isDebugEnabled()) {
334 _log.debug(e, e);
335 }
336
337 throw new UnavailableSourceURIException(
338 "Error accessing source URI", e);
339 }
340
341 List<StartTag> startTags = source.getAllStartTags("a");
342
343 for (StartTag startTag : startTags) {
344 String href = GetterUtil.getString(
345 startTag.getAttributeValue("href"));
346
347 if (href.equals(_targetURI)) {
348 return;
349 }
350 }
351
352 throw new InvalidSourceURIException(
353 "Unable to find target URI in source");
354 }
355
356 private static final Log _log = LogFactoryUtil.getLog(
357 PingbackMethodImpl.class);
358
359 private CommentManager _commentManager = BlogsUtil.getCommentManager();
360 private String _sourceURI;
361 private String _targetURI;
362
363 }