/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.linkback;
import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.HtmlUtil;
import com.liferay.portal.kernel.util.Http;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.ReleaseInfo;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Tuple;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xmlrpc.Response;
import com.liferay.portal.kernel.xmlrpc.XmlRpcException;
import com.liferay.portal.kernel.xmlrpc.XmlRpcUtil;
import com.liferay.portal.util.PropsValues;
import com.liferay.portal.xml.StAXReaderUtil;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.StartTag;
/**
* @author Alexander Chow
*/
public class LinkbackProducerUtil {
public static void sendPingback(String sourceUri, String targetUri)
throws Exception {
_pingbackQueue.add(new Tuple(new Date(), sourceUri, targetUri));
}
public static synchronized void sendQueuedPingbacks()
throws XmlRpcException {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, -1);
Date expiration = cal.getTime();
while (!_pingbackQueue.isEmpty()) {
Tuple tuple = _pingbackQueue.get(0);
Date time = (Date)tuple.getObject(0);
if (time.before(expiration)) {
_pingbackQueue.remove(0);
String sourceUri = (String)tuple.getObject(1);
String targetUri = (String)tuple.getObject(2);
String serverUri = _discoverPingbackServer(targetUri);
if (Validator.isNull(serverUri)) {
continue;
}
if (_log.isInfoEnabled()) {
_log.info(
"XML-RPC pingback " + serverUri + ", source " +
sourceUri + ", target " + targetUri);
}
Response response = XmlRpcUtil.executeMethod(
serverUri, "pingback.ping",
new Object[] {sourceUri, targetUri});
if (_log.isInfoEnabled()) {
_log.info(response.toString());
}
}
else {
break;
}
}
}
public static boolean sendTrackback(
String trackback, Map<String, String> parts)
throws Exception {
if (_log.isInfoEnabled()) {
_log.info("Pinging trackback " + trackback);
}
Http.Options options = new Http.Options();
if (_HTTP_HEADER_VERSION_VERBOSITY_DEFAULT) {
}
else if (_HTTP_HEADER_VERSION_VERBOSITY_PARTIAL) {
options.addHeader(HttpHeaders.USER_AGENT, ReleaseInfo.getName());
}
else {
options.addHeader(
HttpHeaders.USER_AGENT, ReleaseInfo.getServerInfo());
}
options.setLocation(trackback);
options.setParts(parts);
options.setPost(true);
String xml = HttpUtil.URLtoString(options);
if (_log.isDebugEnabled()) {
_log.debug(xml);
}
String error = xml;
XMLStreamReader xmlStreamReader = null;
try {
XMLInputFactory xmlInputFactory =
StAXReaderUtil.getXMLInputFactory();
xmlStreamReader = xmlInputFactory.createXMLStreamReader(
new UnsyncStringReader(xml));
xmlStreamReader.nextTag();
xmlStreamReader.nextTag();
String name = xmlStreamReader.getLocalName();
if (name.equals("error")) {
int status = GetterUtil.getInteger(
xmlStreamReader.getElementText(), 1);
if (status == 0) {
if (_log.isInfoEnabled()) {
_log.info("Trackback accepted");
}
return true;
}
xmlStreamReader.nextTag();
name = xmlStreamReader.getLocalName();
if (name.equals("message")) {
error = xmlStreamReader.getElementText();
}
}
}
finally {
if (xmlStreamReader != null) {
try {
xmlStreamReader.close();
}
catch (Exception e) {
}
}
}
_log.error(
"Error while pinging trackback at " + trackback + ": " + error);
return false;
}
private static String _discoverPingbackServer(String targetUri) {
String serverUri = null;
try {
Http.Options options = new Http.Options();
if (_HTTP_HEADER_VERSION_VERBOSITY_DEFAULT) {
}
else if (_HTTP_HEADER_VERSION_VERBOSITY_PARTIAL) {
options.addHeader(
HttpHeaders.USER_AGENT, ReleaseInfo.getName());
}
else {
options.addHeader(
HttpHeaders.USER_AGENT, ReleaseInfo.getServerInfo());
}
options.setLocation(targetUri);
options.setHead(true);
HttpUtil.URLtoByteArray(options);
Http.Response response = options.getResponse();
serverUri = response.getHeader("X-Pingback");
}
catch (Exception e) {
_log.error("Unable to call HEAD of " + targetUri, e);
}
if (Validator.isNotNull(serverUri)) {
return serverUri;
}
try {
Source clientSource = new Source(HttpUtil.URLtoString(targetUri));
List<StartTag> startTags = clientSource.getAllStartTags("link");
for (StartTag startTag : startTags) {
String rel = startTag.getAttributeValue("rel");
if (StringUtil.equalsIgnoreCase(rel, "pingback")) {
String href = startTag.getAttributeValue("href");
serverUri = HtmlUtil.escape(href);
break;
}
}
}
catch (Exception e) {
_log.error("Unable to call GET of " + targetUri, e);
}
return serverUri;
}
private static final boolean _HTTP_HEADER_VERSION_VERBOSITY_DEFAULT =
StringUtil.equalsIgnoreCase(
PropsValues.HTTP_HEADER_VERSION_VERBOSITY, ReleaseInfo.getName());
private static final boolean _HTTP_HEADER_VERSION_VERBOSITY_PARTIAL =
StringUtil.equalsIgnoreCase(
PropsValues.HTTP_HEADER_VERSION_VERBOSITY, "partial");
private static final Log _log = LogFactoryUtil.getLog(
LinkbackProducerUtil.class);
private static final List<Tuple> _pingbackQueue =
Collections.synchronizedList(new ArrayList<Tuple>());
}