package greencode.kernel;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import greencode.database.DatabaseConnection;
import greencode.exception.ConnectionLost;
import greencode.exception.OperationNotAllowedException;
import greencode.http.Conversation;
import greencode.http.HttpRequest;
import greencode.jscript.DOM;
import greencode.jscript.DOMHandle;
import greencode.jscript.dom.Form;
import greencode.jscript.dom.Window;
import greencode.jscript.dom.function.implementation.SimpleFunction;
import greencode.jscript.dom.window.annotation.PageParameter;
import greencode.kernel.implementation.BootActionImplementation;
import greencode.kernel.serialization.DOMDeserializer;
import greencode.kernel.serialization.DOMSerializer;
import greencode.util.LogMessage;
public final class GreenContext {
private final static ThreadLocal<WeakReference<GreenContext>> greenContext = new ThreadLocal<WeakReference<GreenContext>>();
public static BootActionImplementation getBootAction() { return Cache.bootAction; }
public static GreenContext getInstance() { return greenContext.get().get(); }
private boolean destroyed;
final HttpRequest request;
final HttpServletResponse response;
final WebSocketData webSocketData;
final greencode.jscript.dom.window.annotation.Page currentPageAnnotation;
final public Gson gsonInstance = getGsonInstance();
boolean userLocaleChanged = false;
Locale userLocale;
Properties currentMessagePropertie;
Window currentWindow;
Form requestedForm;
Method requestedMethod;
private DatabaseConnection databaseConnection;
boolean executeAction = true, flushed, forceSynchronization, immediateSync = true;
String[] listAttrSync;
Map<Integer, HashSet<String>> listAttrSyncCache;
GreenContext(HttpServletRequest request, ServletResponse response, FileWeb currentPage, WebSocketData wsData) {
GreenContext.greenContext.set(new WeakReference<GreenContext>(this));
boolean sessionInitialized = wsData != null || request.getSession(false) != null;
this.webSocketData = wsData;
this.response = (HttpServletResponse) response;
this.request = new HttpRequest(request, response, wsData);
if(currentPage == null) {
String servletPath = this.request.getParameter("servletPath");
if(servletPath != null) {
this.currentPageAnnotation = FileWeb.files.get(servletPath).pageAnnotation;
} else {
this.currentPageAnnotation = null;
}
} else
this.currentPageAnnotation = currentPage.pageAnnotation;
if(this.currentPageAnnotation != null) {
if (!(this.currentPageAnnotation.parameters().length == 1 && this.currentPageAnnotation.parameters()[0].name().isEmpty())) {
for (PageParameter p : this.currentPageAnnotation.parameters())
greencode.http.$HttpRequest.getParameters(this.request).put(p.name(), p.value());
}
}
if(!sessionInitialized && getBootAction() != null)
getBootAction().initUserContext(this);
Locale locale = (Locale) this.request.getSession().getAttribute("USER_LOCALE");
if(locale != null) {
this.userLocale = locale;
this.currentMessagePropertie = (Properties) this.request.getSession().getAttribute("CURRENT_MESSAGE_PROPERTIE");
if(this.request.isFirst())
userLocaleChanged = true;
} else {
locale = Locale.getDefault();
if(Message.properties.containsKey(locale.toString()))
setUserLocale(locale);
}
}
public HttpServletResponse getResponse() { exceptionCheck(); return response; }
public HttpRequest getRequest() { exceptionCheck(); return request; }
public Window currentWindow() {
exceptionCheck();
return this.currentWindow;
}
static Map<Integer, Thread> getThreadList(Conversation conversation) {
Map<Integer, Thread> list = (Map<Integer, Thread>) conversation.getAttribute("LIST_THREADS");
if(list == null)
conversation.setAttribute("LIST_THREADS", list = new ConcurrentHashMap<Integer, Thread>());
return list;
}
public void synchronizeDOMGroup(SimpleFunction func) {
exceptionCheck();
this.immediateSync = false;
try {
Thread th = Thread.currentThread();
getThreadList(request.getConversation()).put(th.hashCode(), th);
synchronized(th) {
func.init(this);
this.currentWindow.flush();
th.wait(120000);
}
} catch (Exception e) {
e.printStackTrace();
throw new ConnectionLost(LogMessage.getMessage("green-0011"));
}
this.immediateSync = true;
}
public Method getRequestedMethod() {
exceptionCheck();
return this.requestedMethod;
}
public greencode.jscript.dom.window.annotation.Page currentPageAnnotation() {
exceptionCheck();
return this.currentPageAnnotation == null ? greencode.jscript.dom.$Window.getCurrentPageAnnotation(currentWindow()) : this.currentPageAnnotation;
}
Gson getGsonInstance() {
GsonBuilder instance = new GsonBuilder()
.serializeNulls()
.registerTypeHierarchyAdapter(DOM.class, new DOMSerializer())
.registerTypeHierarchyAdapter(DOM.class, new DOMDeserializer(this));
return instance.create();
}
public DatabaseConnection getDatabaseConnection() {
exceptionCheck();
return this.databaseConnection == null ? this.databaseConnection = new DatabaseConnection() : this.databaseConnection;
}
public void forceSync(boolean force) {
exceptionCheck();
this.forceSynchronization = force;
}
public Locale getUserLocale() {
exceptionCheck();
return this.userLocale;
}
public void setUserLocale(Locale locale) { setUserLocale(locale, false); }
public void setUserLocale(Locale locale, boolean ifEmpty) {
exceptionCheck();
final HttpSession session = request.getSession();
if(ifEmpty && session.getAttribute("CURRENT_MESSAGE_PROPERTIE") != null)
return;
this.userLocaleChanged = true;
this.userLocale = locale;
this.currentMessagePropertie = Message.properties.get(locale.toString());
session.setAttribute("USER_LOCALE", this.userLocale);
session.setAttribute("CURRENT_MESSAGE_PROPERTIE", this.currentMessagePropertie);
}
private void exceptionCheck() {
if(destroyed)
throw new OperationNotAllowedException(LogMessage.getMessage("green-0034"));
}
boolean isForcingSynchronization(final DOM dom, final String property) {
boolean sync;
if(sync = this.forceSynchronization && this.listAttrSyncCache != null) {
HashSet<String> props = this.listAttrSyncCache.get(DOMHandle.getUID(dom));
if(props == null) {
this.listAttrSyncCache.put(DOMHandle.getUID(dom), props = new HashSet<String>());
}
final boolean hasListAttrSyncCache = props != null;
if(this.listAttrSync != null && this.listAttrSync.length > 0) {
sync = false;
if(!hasListAttrSyncCache || !props.contains(property)) {
for (String attr : this.listAttrSync) {
if(attr.equals(property)) {
sync = true;
if(hasListAttrSyncCache)
props.add(property);
break;
}
}
}
}else if(hasListAttrSyncCache) {
if(sync = !props.contains(property))
props.add(property);
}
}
return sync;
}
void destroy() {
try {
if(this.webSocketData != null) {
if(!GreenCodeConfig.Browser.websocketSingleton) {
this.webSocketData.session.close();
} else if(this.webSocketData.session.isOpen()) {
this.webSocketData.session.getBasicRemote().sendText(DOMScanner.getCloseEventId(webSocketData));
}
}
} catch (Exception e) { e.printStackTrace(); }
if(this.databaseConnection != null) {
try {
this.databaseConnection.close();
} catch (SQLException e) { e.printStackTrace(); }
finally {
this.databaseConnection = null;
}
}
this.currentMessagePropertie = null;
this.currentWindow = null;
this.requestedForm = null;
this.requestedMethod = null;
this.userLocale = null;
this.listAttrSync = null;
this.listAttrSyncCache = null;
this.destroyed = true;
greenContext.get().clear();
greenContext.remove();
}
}