package org.hyperic.hq.notifications;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.hyperic.hq.common.SystemException;
import org.hyperic.hq.context.Bootstrap;
import org.hyperic.hq.security.ServerKeystoreConfig;
import org.hyperic.util.http.HQHttpClient;
public class HttpEndpoint extends NotificationEndpoint {
private static final Log log = LogFactory.getLog(HttpEndpoint.class);
private static final String DEFAULT_CONTENT_TYPE = "application/xml";
private static final String DEFAULT_ENCODING = "UTF-8";
private Integer port;
private String hostname;
private String scheme;
private String username;
private String password;
private String contentType;
private String encoding;
private URL url;
private ServerKeystoreConfig keystoreConfig;
private String bodyPrepend;
public HttpEndpoint(String regID, String url, String username, String password, String contentType,
String encoding, String bodyPrepend) {
super(regID);
keystoreConfig = Bootstrap.getBean(ServerKeystoreConfig.class);
try {
this.url = new URL(url);
this.hostname = this.url.getHost();
this.scheme = this.url.getProtocol();
this.port = this.url.getPort();
this.username = username;
this.password = password;
this.contentType = contentType == null ? DEFAULT_CONTENT_TYPE : contentType;
this.encoding = encoding == null ? DEFAULT_ENCODING : encoding;
this.bodyPrepend = bodyPrepend == null ? "" : bodyPrepend + "\n";
} catch (MalformedURLException e) {
throw new SystemException(e);
}
}
@Override
public String toString() {
return new StringBuilder()
.append("[registrationId=").append(getRegistrationId())
.append(",scheme=").append(scheme)
.append(",hostname=").append(hostname)
.append(",port=").append(port)
.append(",url=").append(url)
.append("]")
.toString();
}
@Override
public EndpointStatus publishMessagesInBatch(Collection<InternalAndExternalNotificationReports> messages, List<InternalNotificationReport> failedReports) {
DefaultHttpClient client = null;
try {
if (scheme.equalsIgnoreCase("https")) {
client = new HQHttpClient(keystoreConfig, null, true);
} else {
client = new DefaultHttpClient();
}
final HttpHost targetHost = new HttpHost(hostname, port, scheme);
final AuthScope scope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
client.getCredentialsProvider().setCredentials(scope, creds);
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 60000);
client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 60000);
final AuthCache authCache = new BasicAuthCache();
final BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
final BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
EndpointStatus batchPostingStatus = new EndpointStatus();
for (final InternalAndExternalNotificationReports message : messages) {
final String report = message.getExternalReport();
if (report.contains("\0")) {
log.warn("message body contains a invalid character, message=\n" + report);
}
final BasePostingStatus status = publishMessage(client, report, targetHost, localcontext);
batchPostingStatus.add(status);
if (!status.isSuccessful()) {
failedReports.add(message.getInternalReport());
}
}
return batchPostingStatus;
} finally {
if (client != null) client.getConnectionManager().shutdown();
}
}
private BasePostingStatus publishMessage(DefaultHttpClient client, String message, HttpHost targetHost,
BasicHttpContext localcontext) {
message = bodyPrepend + message;
final boolean debug = log.isDebugEnabled();
final HttpPost post = new HttpPost(url.getPath());
HttpEntity entity;
long time = System.currentTimeMillis();
try {
entity = new StringEntity(message, contentType, encoding);
post.setEntity(entity);
if (debug) log.debug(post.getRequestLine() + ", message=" + message);
final HttpResponse resp = client.execute(targetHost, post, localcontext);
HttpEntity httpRes = resp.getEntity();
// The entire response stream must be read if another connection to the server is made with the current
// client object
final String respBuf= EntityUtils.toString(httpRes);
final StatusLine statusLine = resp.getStatusLine();
if (debug) {
log.debug(statusLine + ", response=[" + respBuf + "]");
}
final int status = statusLine.getStatusCode();
return new HTTPStatus(time,status,respBuf);
} catch (IOException e1) {
log.error("cannot publish to endpoint=" + toString() + ": " + e1,e1);
return new PostingStatus(time,false,e1.getMessage());
}
}
@Override
public boolean canPublish() {
return true;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public URL getUrl() {
return url;
}
public void setUrl(URL url) {
this.url = url;
}
public ServerKeystoreConfig getKeystoreConfig() {
return keystoreConfig;
}
public void setKeystoreConfig(ServerKeystoreConfig keystoreConfig) {
this.keystoreConfig = keystoreConfig;
}
}