001
014
015 package com.liferay.portlet.blogs.util;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.servlet.HttpHeaders;
021 import com.liferay.portal.kernel.util.GetterUtil;
022 import com.liferay.portal.kernel.util.HtmlUtil;
023 import com.liferay.portal.kernel.util.Http;
024 import com.liferay.portal.kernel.util.HttpUtil;
025 import com.liferay.portal.kernel.util.ReleaseInfo;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Tuple;
028 import com.liferay.portal.kernel.util.Validator;
029 import com.liferay.portal.kernel.xmlrpc.Response;
030 import com.liferay.portal.kernel.xmlrpc.XmlRpcException;
031 import com.liferay.portal.kernel.xmlrpc.XmlRpcUtil;
032 import com.liferay.portal.util.PropsValues;
033 import com.liferay.portal.xml.StAXReaderUtil;
034
035 import java.util.ArrayList;
036 import java.util.Calendar;
037 import java.util.Collections;
038 import java.util.Date;
039 import java.util.List;
040 import java.util.Map;
041
042 import javax.xml.stream.XMLInputFactory;
043 import javax.xml.stream.XMLStreamReader;
044
045 import net.htmlparser.jericho.Source;
046 import net.htmlparser.jericho.StartTag;
047
048
051 public class LinkbackProducerUtil {
052
053 public static void sendPingback(String sourceUri, String targetUri)
054 throws Exception {
055
056 _pingbackQueue.add(new Tuple(new Date(), sourceUri, targetUri));
057 }
058
059 public static synchronized void sendQueuedPingbacks()
060 throws XmlRpcException {
061
062 Calendar cal = Calendar.getInstance();
063
064 cal.add(Calendar.MINUTE, -1);
065
066 Date expiration = cal.getTime();
067
068 while (!_pingbackQueue.isEmpty()) {
069 Tuple tuple = _pingbackQueue.get(0);
070
071 Date time = (Date)tuple.getObject(0);
072
073 if (time.before(expiration)) {
074 _pingbackQueue.remove(0);
075
076 String sourceUri = (String)tuple.getObject(1);
077 String targetUri = (String)tuple.getObject(2);
078
079 String serverUri = _discoverPingbackServer(targetUri);
080
081 if (Validator.isNull(serverUri)) {
082 continue;
083 }
084
085 if (_log.isInfoEnabled()) {
086 _log.info(
087 "XML-RPC pingback " + serverUri + ", source " +
088 sourceUri + ", target " + targetUri);
089 }
090
091 Response response = XmlRpcUtil.executeMethod(
092 serverUri, "pingback.ping",
093 new Object[] {sourceUri, targetUri});
094
095 if (_log.isInfoEnabled()) {
096 _log.info(response.toString());
097 }
098 }
099 else {
100 break;
101 }
102 }
103 }
104
105 public static boolean sendTrackback(
106 String trackback, Map<String, String> parts)
107 throws Exception {
108
109 if (_log.isInfoEnabled()) {
110 _log.info("Pinging trackback " + trackback);
111 }
112
113 Http.Options options = new Http.Options();
114
115 if (_HTTP_HEADER_VERSION_VERBOSITY_DEFAULT) {
116 }
117 else if (_HTTP_HEADER_VERSION_VERBOSITY_PARTIAL) {
118 options.addHeader(HttpHeaders.USER_AGENT, ReleaseInfo.getName());
119 }
120 else {
121 options.addHeader(
122 HttpHeaders.USER_AGENT, ReleaseInfo.getServerInfo());
123 }
124
125 options.setLocation(trackback);
126 options.setParts(parts);
127 options.setPost(true);
128
129 String xml = HttpUtil.URLtoString(options);
130
131 if (_log.isDebugEnabled()) {
132 _log.debug(xml);
133 }
134
135 String error = xml;
136
137 XMLStreamReader xmlStreamReader = null;
138
139 try {
140 XMLInputFactory xmlInputFactory =
141 StAXReaderUtil.getXMLInputFactory();
142
143 xmlStreamReader = xmlInputFactory.createXMLStreamReader(
144 new UnsyncStringReader(xml));
145
146 xmlStreamReader.nextTag();
147 xmlStreamReader.nextTag();
148
149 String name = xmlStreamReader.getLocalName();
150
151 if (name.equals("error")) {
152 int status = GetterUtil.getInteger(
153 xmlStreamReader.getElementText(), 1);
154
155 if (status == 0) {
156 if (_log.isInfoEnabled()) {
157 _log.info("Trackback accepted");
158 }
159
160 return true;
161 }
162
163 xmlStreamReader.nextTag();
164
165 name = xmlStreamReader.getLocalName();
166
167 if (name.equals("message")) {
168 error = xmlStreamReader.getElementText();
169 }
170 }
171 }
172 finally {
173 if (xmlStreamReader != null) {
174 try {
175 xmlStreamReader.close();
176 }
177 catch (Exception e) {
178 }
179 }
180 }
181
182 _log.error(
183 "Error while pinging trackback at " + trackback + ": " + error);
184
185 return false;
186 }
187
188 private static String _discoverPingbackServer(String targetUri) {
189 String serverUri = null;
190
191 try {
192 Http.Options options = new Http.Options();
193
194 if (_HTTP_HEADER_VERSION_VERBOSITY_DEFAULT) {
195 }
196 else if (_HTTP_HEADER_VERSION_VERBOSITY_PARTIAL) {
197 options.addHeader(
198 HttpHeaders.USER_AGENT, ReleaseInfo.getName());
199 }
200 else {
201 options.addHeader(
202 HttpHeaders.USER_AGENT, ReleaseInfo.getServerInfo());
203 }
204
205 options.setLocation(targetUri);
206 options.setHead(true);
207
208 HttpUtil.URLtoByteArray(options);
209
210 Http.Response response = options.getResponse();
211
212 serverUri = response.getHeader("X-Pingback");
213 }
214 catch (Exception e) {
215 _log.error("Unable to call HEAD of " + targetUri, e);
216 }
217
218 if (Validator.isNotNull(serverUri)) {
219 return serverUri;
220 }
221
222 try {
223 Source clientSource = new Source(HttpUtil.URLtoString(targetUri));
224
225 List<StartTag> startTags = clientSource.getAllStartTags("link");
226
227 for (StartTag startTag : startTags) {
228 String rel = startTag.getAttributeValue("rel");
229
230 if (StringUtil.equalsIgnoreCase(rel, "pingback")) {
231 String href = startTag.getAttributeValue("href");
232
233 serverUri = HtmlUtil.escape(href);
234
235 break;
236 }
237 }
238 }
239 catch (Exception e) {
240 _log.error("Unable to call GET of " + targetUri, e);
241 }
242
243 return serverUri;
244 }
245
246 private static final boolean _HTTP_HEADER_VERSION_VERBOSITY_DEFAULT =
247 StringUtil.equalsIgnoreCase(
248 PropsValues.HTTP_HEADER_VERSION_VERBOSITY, ReleaseInfo.getName());
249
250 private static final boolean _HTTP_HEADER_VERSION_VERBOSITY_PARTIAL =
251 StringUtil.equalsIgnoreCase(
252 PropsValues.HTTP_HEADER_VERSION_VERBOSITY, "partial");
253
254 private static final Log _log = LogFactoryUtil.getLog(
255 LinkbackProducerUtil.class);
256
257 private static final List<Tuple> _pingbackQueue =
258 Collections.synchronizedList(new ArrayList<Tuple>());
259
260 }