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