/*
* This file is part of gwap, an open platform for games with a purpose
*
* Copyright (C) 2013
* Project play4science
* Lehr- und Forschungseinheit für Programmier- und Modellierungssprachen
* Ludwig-Maximilians-Universität München
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gwap.tools;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.log.Log;
import org.jboss.seam.util.RandomStringUtils;
import org.jboss.seam.web.AbstractResource;
/**
* Responsible for storing and retrieving hashes for images.
*
* @author Fabian Kneißl
*/
public abstract class AbstractAccessBean extends AbstractResource implements Serializable {
protected static final long serialVersionUID = 1L;
protected static final int URL_LIFETIME_SECS = 600; // 10 Minutes
protected static final int HASH_LENGTH = 40;
@Logger protected Log log;
// Map<temporary image hash, real path>
protected Map<String, HashBean> hashMap = new ConcurrentHashMap<String, HashBean>();
protected List<HashBean> hashList = new ArrayList<HashBean>();
protected Boolean cleanupInProgress = false;
abstract protected String hashToUrl(String hash);
@Override
public abstract String getResourcePath();
public String createUrl(String filePath) {
String hash = createNewHash();
HashBean value = new HashBean(filePath, hash);
hashMap.put(hash, value);
hashList.add(value);
log.info("createUrl(#0) => #1", filePath, hash);
return hashToUrl(hash);
}
public String getPath(String hash) {
cleanup();
if (hash != null) {
HashBean hashBean = hashMap.get(hash);
if (hashBean != null)
return hashBean.getPath();
}
return null;
}
private void cleanup() {
synchronized (cleanupInProgress) {
if (cleanupInProgress) // Check if cleanup is running, if yes, just return
return;
else
cleanupInProgress = true;
}
Calendar beforeCal = GregorianCalendar.getInstance();
beforeCal.add(Calendar.SECOND, -URL_LIFETIME_SECS);
Date timeout = beforeCal.getTime();
while (hashList.size() > 0 &&
timeout.after(hashList.get(0).getDate())) {
HashBean hashBean = hashList.remove(0);
hashMap.remove(hashBean.getHash());
}
synchronized (cleanupInProgress) {
cleanupInProgress = false;
}
}
private String createNewHash() {
return RandomStringUtils.randomAlphanumeric(HASH_LENGTH);
}
@Override
public abstract void getResource(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException;
protected static int writeTo(InputStream in, OutputStream out) throws IOException {
int bytesWritten = 0;
int bufSize = 1024; // 1KB
byte[] buffer = new byte[bufSize];
int n;
n = in.read(buffer);
while (!(n < buffer.length)) {
bytesWritten+=1024;
out.write(buffer, 0, bufSize);
out.flush();
n = in.read(buffer);
}
if (n > 0) {
out.write(buffer, 0, n);
bytesWritten+=n;
}
return bytesWritten;
}
}