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