/**
* MailArchiver is an application that provides services for storing and managing e-mail messages through a Web Services SOAP interface.
* Copyright (C) 2012 Marcio Andre Scholl Levien and Fernando Alberto Reuter Wendt and Jose Ronaldo Nogueira Fonseca Junior
*
* 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 .
*/
/******************************************************************************\
*
* This product was developed by
*
* SERVIÇO FEDERAL DE PROCESSAMENTO DE DADOS (SERPRO),
*
* a government company established under Brazilian law (5.615/70),
* at Department of Development of Porto Alegre.
*
\******************************************************************************/
package serpro.mailarchiver.session;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import serpro.mailarchiver.service.Utils;
import serpro.mailarchiver.service.dto.TFault;
import serpro.mailarchiver.util.Logger;
import serpro.mailarchiver.util.LuceneIndex;
@Configurable(preConstruction=true)
public class Session {
private static final Logger log = Logger.getLocalLogger();
@Autowired
private Utils utils;
private static final InheritableThreadLocal threadSession = new InheritableThreadLocal();
public static void setThreadSession(Session session) {
threadSession.set(session);
}
public static Session getThreadSession() {
return threadSession.get();
}
public static String internalizeFolderId(String id) {
if((id == null) || id.isEmpty() || id.endsWith("home")) {
return getHomeFolderId();
}
else if(id.endsWith("inbox")) {
return getInboxFolderId();
}
else if(id.endsWith("outbox")) {
return getOutboxFolderId();
}
else if(id.endsWith("drafts")) {
return getDraftsFolderId();
}
else if(id.endsWith("sent")) {
return getSentFolderId();
}
else if(id.endsWith("spam")) {
return getSpamFolderId();
}
else if(id.endsWith("trash")) {
return getTrashFolderId();
}
else {
return id;
}
}
public static String getHomeFolderId() {
return "_" + getThreadSession().userId.toLowerCase() + "_home";
}
public static String getInboxFolderId() {
return "_" + getThreadSession().userId.toLowerCase() + "_inbox";
}
public static String getOutboxFolderId() {
return "_" + getThreadSession().userId.toLowerCase() + "_outbox";
}
public static String getDraftsFolderId() {
return "_" + getThreadSession().userId.toLowerCase() + "_drafts";
}
public static String getSentFolderId() {
return "_" + getThreadSession().userId.toLowerCase() + "_sent";
}
public static String getSpamFolderId() {
return "_" + getThreadSession().userId.toLowerCase() + "_spam";
}
public static String getTrashFolderId() {
return "_" + getThreadSession().userId.toLowerCase() + "_trash";
}
public static LuceneIndex getLuceneIndex() {
return getThreadSession().index;
}
//--------------------------------------------------------------------------
private final String sessionId;
private final String userId;
private final LuceneIndex index;
public Session(String userId) throws Exception {
try {
sessionId = UUID.randomUUID().toString();
this.userId = userId;
Session.setThreadSession(this);
SessionMap.put(this);
utils.provideMailHome(userId);
index = LuceneIndex.getInstance(userId);
Path indexAbsolutePath = index.getAbsolutePath();
if(Files.notExists(indexAbsolutePath)) {
Files.createDirectory(indexAbsolutePath);
}
startGateKeeper();
log.info("new session:%s user:%s", sessionId, userId);
}
catch(Exception ex) {
SessionMap.remove(this);
Session.setThreadSession(null);
throw ex;
}
}
public String getUserId() {
return userId;
}
public String getSessionId() {
return sessionId;
}
public LuceneIndex getIndex() {
return index;
}
//--------------------------------------------------------------------------
private final BlockingQueue queue = new LinkedBlockingQueue();
private final CyclicBarrier barrier = new CyclicBarrier(2);
final void startGateKeeper() {
new Thread() {
@Override
public void run() {
for(;;) {
MutableBoolean waitSlot = null;
try {
waitSlot = queue.take();
}
catch(InterruptedException ex) {
log.warn(ex);
}
synchronized(waitSlot) {
waitSlot.setValue(true);
waitSlot.notify();
}
try {
barrier.await();
}
catch(InterruptedException ex) {
log.warn(ex);
}
catch(BrokenBarrierException ex) {
log.warn(ex);
}
barrier.reset();
}
}
}
.start();
}
public void enroll() {
final MutableBoolean waitSlot = new MutableBoolean(false);
try {
queue.put(waitSlot);
}
catch(InterruptedException ex) {
log.warn(ex);
}
synchronized(waitSlot) {
while(waitSlot.isFalse()) {
try {
waitSlot.wait();
}
catch(InterruptedException ex) {
log.warn(ex);
}
}
}
}
public void depart() {
try {
barrier.await();
}
catch(InterruptedException ex) {
log.warn(ex);
}
catch(BrokenBarrierException ex) {
log.warn(ex);
}
}
//--------------------------------------------------------------------------
private TFault lastFault;
public TFault getLastFault() {
return lastFault;
}
public void setLastFault(TFault lastFault) {
this.lastFault = lastFault;
}
//--------------------------------------------------------------------------
private final Map statistics = new TreeMap() {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for(Entry entry : entrySet()) {
if(sb.length() > 0) {
sb.append("\n");
}
sb.append(entry.getKey()).append(": ").append(entry.getValue());
}
return sb.toString();
}
};
public void incStatistics(String name) {
Long n = statistics.get(name);
if(n == null) {
statistics.put(name, 1L);
}
else {
statistics.put(name, ++n);
}
}
public void clearStatistics() {
statistics.clear();
}
public Map getStatistics() {
return statistics;
}
}