blob: 08f07e8a10ce95fefb24be2ef5e7d5331b0e08af [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 GitHub Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Kevin Sawicki (GitHub Inc.) - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.commons.identity.core.gravatar;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
/**
* Class that loads and stores gravatars.
*
* @author Kevin Sawicki (kevin@github.com)
*/
public class GravatarStore implements Serializable, ISchedulingRule {
/**
* TIMEOUT
*/
public static final int TIMEOUT = 30 * 1000;
/**
* BUFFER_SIZE
*/
public static final int BUFFER_SIZE = 8192;
public enum Rating {
G, PG, R, X
};
private static final long serialVersionUID = 6084425297832914970L;
private long lastRefresh = 0L;
private final String url;
private Map<String, Gravatar> avatars;
/**
* Create gravatar store
*/
public GravatarStore() {
this(IGravatarConstants.URL);
}
/**
* Create gravatar store
*
* @param url
*/
public GravatarStore(String url) {
Assert.isNotNull(url, "Url cannot be null"); //$NON-NLS-1$
// Ensure trailing slash
if (!url.endsWith("/")) { //$NON-NLS-1$
url += "/"; //$NON-NLS-1$
}
this.url = url;
}
public boolean isCacheEnabled() {
return avatars != null;
}
public void setCacheEnabled(boolean cacheEnabled) {
if (cacheEnabled && avatars == null) {
avatars = Collections.synchronizedMap(new HashMap<String, Gravatar>());
} else if (!cacheEnabled && avatars != null) {
avatars = null;
}
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#getRefreshTime()
*/
public long getRefreshTime() {
return this.lastRefresh;
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#containsGravatar(java.lang.String)
*/
public boolean containsGravatar(String hash) {
return hash != null && avatars != null ? this.avatars.containsKey(hash) : false;
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#scheduleRefresh()
*/
public GravatarStore scheduleRefresh() {
Job refresh = new Job(Messages.GravatarStore_RefreshJobName) {
@Override
protected IStatus run(IProgressMonitor monitor) {
refresh(monitor);
return Status.OK_STATUS;
}
};
refresh.setRule(this);
refresh.schedule();
return this;
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#refresh(org.eclipse.core.runtime.IProgressMonitor)
*/
public GravatarStore refresh(IProgressMonitor monitor) {
if (this.avatars == null) {
return this;
}
if (monitor == null) {
monitor = new NullProgressMonitor();
}
String[] entries = null;
synchronized (this.avatars) {
entries = new String[this.avatars.size()];
entries = this.avatars.keySet().toArray(entries);
}
monitor.beginTask("", entries.length); //$NON-NLS-1$
for (String entry : entries) {
if (monitor.isCanceled()) {
break;
}
monitor.setTaskName(MessageFormat.format(Messages.GravatarStore_LoadingAvatar, entry));
try {
loadGravatarByHash(entry);
} catch (IOException ignore) {
}
monitor.worked(1);
}
monitor.done();
this.lastRefresh = System.currentTimeMillis();
return this;
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByHash(java.lang.String,
* org.eclipse.mylyn.internal.commons.identity.core.gravatar.IGravatarCallback)
*/
public GravatarStore loadGravatarByHash(final String hash, final IGravatarCallback callback) {
String title = MessageFormat.format(Messages.GravatarStore_LoadingAvatar, hash);
Job job = new Job(title) {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
Gravatar avatar = loadGravatarByHash(hash);
if (avatar != null && callback != null) {
callback.loaded(avatar);
}
} catch (IOException e) {
if (callback != null) {
callback.error(e);
}
}
return Status.OK_STATUS;
}
};
job.setRule(this);
job.schedule();
return this;
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByEmail(java.lang.String,
* org.eclipse.mylyn.internal.commons.identity.core.gravatar.IGravatarCallback)
*/
public GravatarStore loadGravatarByEmail(String email, IGravatarCallback callback) {
loadGravatarByHash(GravatarUtils.getHash(email), callback);
return this;
}
public Gravatar loadGravatarByHash(String hash) throws IOException {
return loadGravatarByHash(hash, -1, null);
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByHash(java.lang.String)
*/
public Gravatar loadGravatarByHash(String hash, int size, Rating rating) throws IOException {
Assert.isLegal(size == -1 || (size >= 1 && size <= 512), "size must have a value of -1 or between 1 and 512"); //$NON-NLS-1$
if (!GravatarUtils.isValidHash(hash)) {
return null;
}
Gravatar avatar = null;
String location = this.url + hash + "?d=404"; //$NON-NLS-1$
if (size != -1) {
location += "&s=" + size; //$NON-NLS-1$
}
if (rating != null) {
location += "&r=" + rating.name().toLowerCase(); //$NON-NLS-1$
}
HttpURLConnection connection = (HttpURLConnection) new URL(location).openConnection();
connection.setConnectTimeout(TIMEOUT);
connection.setUseCaches(false);
connection.connect();
if (connection.getResponseCode() != 200) {
return null;
}
ByteArrayOutputStream output = new ByteArrayOutputStream();
InputStream input = connection.getInputStream();
try {
byte[] buffer = new byte[BUFFER_SIZE];
int read = -1;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
} finally {
try {
input.close();
} catch (IOException ignore) {
}
}
avatar = new Gravatar(hash, System.currentTimeMillis(), output.toByteArray());
if (this.avatars != null) {
this.avatars.put(hash, avatar);
}
return avatar;
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#loadGravatarByEmail(java.lang.String)
*/
public Gravatar loadGravatarByEmail(String email) throws IOException {
return loadGravatarByHash(GravatarUtils.getHash(email));
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#getGravatarByHash(java.lang.String)
*/
public Gravatar getGravatarByHash(String hash) {
return hash != null && avatars != null ? this.avatars.get(hash) : null;
}
/**
* @see org.eclipse.mylyn.internal.commons.identity.gravatar.IGravatarStore#getGravatarByEmail(java.lang.String)
*/
public Gravatar getGravatarByEmail(String email) {
return getGravatarByHash(GravatarUtils.getHash(email));
}
/**
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
public boolean contains(ISchedulingRule rule) {
return this == rule;
}
/**
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
public boolean isConflicting(ISchedulingRule rule) {
return this == rule;
}
}