package org.jblooming.waf.view; import org.jblooming.PlatformRuntimeException; import org.jblooming.ontology.Identifiable; import org.jblooming.operator.Operator; import org.jblooming.page.Page; import org.jblooming.persistence.PersistenceHome; import org.jblooming.persistence.ThreadLocalPersistenceContextCarrier; import org.jblooming.persistence.exceptions.PersistenceException; import org.jblooming.persistence.hibernate.PersistenceContext; import org.jblooming.security.InvalidTokenException; import org.jblooming.utilities.*; import org.jblooming.waf.ActionController; import org.jblooming.waf.ScreenArea; import org.jblooming.waf.ScreenRoot; import org.jblooming.waf.SessionState; import org.jblooming.waf.constants.Commands; import org.jblooming.waf.constants.Fields; import org.jblooming.waf.html.container.ButtonBar; import org.jblooming.waf.html.core.HtmlBootstrap; import org.jblooming.waf.html.core.JspIncluder; import org.jblooming.waf.html.display.DeletePreviewer; import org.jblooming.waf.html.display.HeaderFooter; import org.jblooming.waf.html.layout.Skin; import org.jblooming.waf.html.state.Form; import org.jblooming.waf.settings.Application; import org.jblooming.waf.settings.ApplicationState; import org.jblooming.waf.settings.PlatformConfiguration; import org.jblooming.waf.settings.I18n; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.PageContext; import java.io.IOException; import java.util.*; public class PageState extends PageSeed { private Operator operator = null; // added after reforma 7/10/2010 private static ThreadLocal<PageState> __threadLocalPageState = new ThreadLocal<PageState>() { protected PageState initialValue() { return null; } }; public Map<String, Page> pages = new HashTable(); public SessionState sessionState; public Identifiable mainObject; public Map attributes = new HashMap(); public Set initedElements = new HashSet(); /** * this list is used to manage communication from controller to the page. CE errors are not inserted ther, but displayed automatically by the component */ public List<Message> messagesFromController = new ArrayList<Message>(); /** * elements of the screen */ private Form form; private HeaderFooter headerFooter; /** * template composition */ public boolean screenRunning = false; /** * stopPageAfterController inhibit the call to page generation * it should be set to true when a page/controller is called by ajax. E.G removing a line from a list * without refreshing the page and having this command inside the controller */ public boolean stopPageAfterController = false; public ScreenArea runningControllerScreenArea; private Stack screenAreas = new Stack(); public ScreenRoot rootScreen; /** * display validation */ public HtmlBootstrap.HtmlBootstrappers htmlBootstrappers = new HtmlBootstrap.HtmlBootstrappers(); private String focusedObjectDomId = null; private JspIncluder mainJspIncluder; private ButtonBar mainButtonBar; public DeletePreviewer deletePreviewer; public boolean multipart = false; public PageState(String url, SessionState sm) { if (url == null || url.trim().length() == 0) throw new PlatformRuntimeException("ViewHlp::buildView invalid parameters."); __threadLocalPageState.set(this); setHref(url); setSessionState(sm); } public void setFocusedObjectDomId(String domId) { focusedObjectDomId = domId; } public String getColor(String colorName) { return getI18n("COLOR_" + colorName); } /** * @deprecated use I8n.get(name) * @param name * @return */ public String getI18n(String name) { return I18n.get(name); } public SessionState getSessionState() { return sessionState; } public void setSessionState(SessionState sessionState) { this.sessionState = (SessionState) sessionState; } public Identifiable getMainObject() { return mainObject; } public void setMainObject(Identifiable mainObject) { this.mainObject = mainObject; } public Object getAttribute(String key) { return attributes.get(key); } public void setAttribute(String key, Object value) { attributes.put(key, value); } /** * Gte the pageState from threadLocal * @return */ public static PageState getCurrentPageState() { return __threadLocalPageState.get(); } /** * @deprecated use without request getCurrentPageState(). DO NOT REMOVE FOR BACK COMPATIBILITY (e.g.: custom portlets) * @param request * @return */ public static PageState getCurrentPageState(HttpServletRequest request) { return getCurrentPageState(); } public PageState perform(HttpServletRequest request, HttpServletResponse response) { while (!screenAreas.empty()) { try { ScreenArea screenArea = (ScreenArea) screenAreas.pop(); ActionController controller = screenArea.controller; runningControllerScreenArea = screenArea; if (controller != null) { controller.perform(request, response); } } catch (Exception e) { throw new PlatformRuntimeException(e); } } if (validEntries()) { ThreadLocalPersistenceContextCarrier carrier = PersistenceContext.threadLocalPersistenceContextCarrier.get(); if (carrier != null) { for (PersistenceContext pc : carrier.persistenceContextMap.values()) { pc.checkPoint(); } } else { System.out.println("Carrier is null"); } } return this; } public void setForm(Form f) { this.form = f; } public Form getForm() { return form; } public void focusToHtml(PageContext pageContext) throws IOException { if (focusedObjectDomId != null) pageContext.getOut().print("<script>$(document).ready(function(){$('#" + focusedObjectDomId + "').focus()});</script>"); } public PageState registerPart(ScreenArea screenArea) { this.screenAreas.push(screenArea); return this; } public String toString() { return "\nScreenBasic = " + rootScreen; } public void toHtml(PageContext pageContext) { if (rootScreen == null) throw new PlatformRuntimeException("PageState calling toHtml on rootScreen==null"); if (!stopPageAfterController) rootScreen.toHtml(pageContext); } public static void buildPartsAndClientEntries(HttpServletRequest request, PageState pageState) { ClientEntries clientEntries = new ClientEntries(); Enumeration parameters = request.getParameterNames(); while (parameters.hasMoreElements()) { String paramName = (String) parameters.nextElement(); if (paramName != null) { String viewPropertyValue = request.getParameter(paramName).trim(); if (Commands.COMMAND.equals(paramName)) { pageState.setCommand(request.getParameter(paramName)); } else if (paramName.equals(Fields.OBJECT_ID)) { pageState.setMainObjectId(viewPropertyValue); } else if (paramName.equals(Fields.POPUP)) { pageState.setPopup(true); } else { clientEntries.addEntry(new ClientEntry(paramName, StringUtilities.arrayToString(request.getParameterValues(paramName), ",").trim())); } } } pageState.setClientEntries(clientEntries); } public HeaderFooter getHeaderFooter() { if (headerFooter == null) headerFooter = new HeaderFooter(this); return headerFooter; } public Skin getSkin() { return sessionState.getSkin(); } public Page getPage() { return pages.get("DEFAULT_PAGE"); } public void setPage(Page page) { this.pages.put("DEFAULT_PAGE", page); } private void updateSeed(PageSeed newSeed) { this.href = newSeed.getHref(); this.setMainObjectId(newSeed.getMainObjectId()); setClientEntries(newSeed.getClientEntries()); this.command = newSeed.getCommand(); setLoginRequiring(newSeed.isLoginRequiring()); setPopup(newSeed.isPopup()); } /** * @see org.jblooming.waf.ScreenBasic changeBody(org.jblooming.waf.view.PageState, org.jblooming.waf.view.PageSeed) * WARNING: do not use contextPath in newPageseed: * CORRECT: newpageseed= new PageSeed("/commons/bblabla/xxx.jsp"); * NOT CORRECT: newpageseed= pagestate.pageFromCommonRoot("/bblabla/xxx.jsp"); * NOT CORRECT: newpageseed= pagestate.pageFromRoot("xxx.jsp"); */ public void redirect(PageSeed newSeed) { updateSeed(newSeed); final ScreenArea basicScreen = this.runningControllerScreenArea; ScreenRoot lw = basicScreen.parent; this.screenRunning = false; lw.urlToInclude = newSeed.href; } public void setApplication(Application application) { sessionState.setApplication(application); } public Application getApplication() { return sessionState.getApplication(); } //the new pageSeed is created from history's one if matching // but the href is taken from the one passed as in case of pageState.redirect // you don't have to put the context path public void backTo(PageSeed filterByUrl) { PageSeed backTo = filterByUrl.getNewInstance(); boolean found = false; for (int i = sessionState.pageHistory.history.size() - 1; i >= 0 && !found; i--) { String absoluteHref = sessionState.pageHistory.history.get(i).href; if (absoluteHref.endsWith(filterByUrl.href)) { backTo = sessionState.pageHistory.history.get(i).getNewInstance(); backTo.href = filterByUrl.href; found = true; break; } } redirect(backTo); } public PageSeed thisPage(HttpServletRequest request) { int i = href.indexOf("?"); if (i == -1) i = href.length(); String newHref = href.substring(0, i); //if there is no path, do not touch it if (!(newHref.indexOf("/") == -1)) newHref = request.getContextPath() + newHref; return new PageSeed(newHref); } public void setMainJspIncluder(JspIncluder jspIncluder) { this.mainJspIncluder = jspIncluder; } public JspIncluder getMainJspIncluder() { return mainJspIncluder; } public PageSeed pageInThisFolder(String page, HttpServletRequest request) { String realURI = HttpUtilities.realURI(request); String href = request.getContextPath() + realURI.substring(0, realURI.lastIndexOf("/")) + "/" + page; return new PageSeed(href); } /** * @param request * @return the pagesed representing the current part. It is used tipically in the webParts */ public PageSeed pagePart(HttpServletRequest request) { String realURI = HttpUtilities.realURI(request); return new PageSeed(request.getContextPath() + realURI); } /** * @param page * @return the page from the root of web application */ public PageSeed pageFromWebApp(String page) { if (!page.startsWith("/")) page = "/" + page; return new PageSeed(ApplicationState.contextPath + page); } /** * @param page * @return the page from the root of applications */ public PageSeed pageFromApplications(String page) { if (!page.startsWith("/")) page = "/" + page; return new PageSeed(ApplicationState.contextPath + "/applications" + page); } /** * @param page * @return the page from root of current application */ public PageSeed pageFromRoot(String page) { if (!page.startsWith("/")) page = "/" + page; String rootF = getApplication().getRootFolder(); if (!rootF.startsWith("/")) rootF = "/" + rootF; return new PageSeed(ApplicationState.contextPath + rootF + page); } /** * @param page * @return the page from root of current application with context path */ public PageSeed pageFromCommonsRoot(String page) { if (!page.startsWith("/")) page = "/" + page; return new PageSeed(ApplicationState.contextPath + "/commons" + page); } public void setButtonBar(ButtonBar bb2) { this.mainButtonBar = bb2; } public ButtonBar getButtonBar() { return mainButtonBar; } public boolean validEntries() { return getClientEntries().validEntries(); } public ClientEntry getEntryOrDefault(String name) throws PersistenceException { ClientEntry ce = getEntry(name); ce.persistInOptions = true; if (ce.name == null) { Operator op = getLoggedOperator(); String option = null; if (op!=null) option=op.getOptionOrDefault(name); if (option != null) { ce.name = name; ce.setValue(option); addClientEntry(ce); } } return ce; } public ClientEntry getEntryOrDefault(String name, String defaultValue) throws PersistenceException { ClientEntry ce = getEntryOrDefault(name); if (ce.stringValueNullIfEmpty() == null) { ce.name = name; ce.setValue(defaultValue); addClientEntry(ce); } return ce; } public void saveEntriesInDefaults() throws PersistenceException { Operator op = getLoggedOperator(); if (op != null) { boolean changedSomeOption = false; for (ClientEntry ce : getClientEntriesSet()) { if (ce.persistInOptions) { String value = ce.stringValueNullIfEmpty(); String optValue = op.getOption(ce.name); if (value != null && !value.equals(optValue)) { op.putOption(ce.name, ce.stringValueNullIfEmpty()); changedSomeOption = true; } else if (value == null && optValue != null) { op.getOptions().remove(ce.name); changedSomeOption = true; } } } if (changedSomeOption) { op.store(); } } } public void saveInHistory() { sessionState.pageHistory.saveInHistory(this); } public void saveInHistoryAndResetCommand() { command = null; sessionState.pageHistory.saveInHistory(this); } public boolean saveInHistoryIfNeeded() { boolean didSaveItHere = false; if (!isPopup() && JSP.ex(command) && !Commands.EDIT.equals(getCommand()) && !Commands.FIND.equals(getCommand()) && !Commands.SAVE.equals(getCommand()) && !Commands.DELETE.equals(getCommand()) && !Commands.DELETE_PREVIEW.equals(getCommand()) && !Commands.ADD.equals(getCommand()) ) { saveInHistory(); didSaveItHere = true; } return didSaveItHere; } public PageSeed getNewInstance() { PageSeed ps = super.getNewInstance(); // pageState differs satanically from pageSeed in that its href by default is not prefixed with context path ps.href = ApplicationState.contextPath + ps.href; return ps; } public String tokenCreate(String tokenName) { String token = StringUtilities.generatePassword(20); this.sessionState.setAttribute(tokenName, token); return token; } public static String TOKEN = "__tk"; public void tokenCreate(String tokenName, PageSeed destination) { destination.addClientEntry(TOKEN, tokenCreate(tokenName)); } public void tokenValidate(String tokenName) throws InvalidTokenException { tokenValidate(tokenName, true); } public void tokenValidate(String tokenName, boolean removeToken) throws InvalidTokenException { String token = sessionState.getAttribute(tokenName) + ""; if (removeToken) sessionState.getAttributes().remove(tokenName); String s = getEntry(TOKEN).stringValueNullIfEmpty(); if (!token.equals(s)) { addMessageError(getI18n("INVALID_SECURITY_TOKEN")); throw new InvalidTokenException("INVALID_SECURITY_TOKEN"); } } public void tokenClone(String tokenName, PageSeed destination) { String sesTk = sessionState.getAttribute(tokenName) + ""; destination.addClientEntry(TOKEN, sesTk); } public String tokenGetCurrent(String tokenName) { return sessionState.getAttribute(tokenName) + ""; } public String tokenGetCurrent() { return this.getEntry(TOKEN).stringValueNullIfEmpty(); } public void setError(String errorCode) { //create an error to force FCF to rollback transaction ClientEntry ce = new ClientEntry("__ERROR", "error"); ce.errorCode=JSP.ex(ce)? errorCode :"JSON Error"; addClientEntry(ce); } //---------------------------------------------------- MESSAGES FROM CONTROLLER MANAGEMENT ------------ START --------------------------------------- public static enum MessageType {ERROR,WARNING,INFO, OK } public Message addMessageError(String message) { Message message1 = new Message(MessageType.ERROR, message); messagesFromController.add(message1); return message1; } public Message addMessageWarning(String message) { Message message1 = new Message(MessageType.WARNING, message); messagesFromController.add(message1); return message1; } public Message addMessageInfo(String message) { Message message1 = new Message(MessageType.INFO, message); messagesFromController.add(message1); return message1; } public Message addMessageOK(String message) { Message message1 = new Message(MessageType.OK, message); messagesFromController.add(message1); return message1; } public static class Message { public MessageType type; public String title; public String message; public Message(MessageType type, String message) { this.type = type; this.message = message; } } //---------------------------------------------------- MESSAGES FROM CONTROLLER MANAGEMENT ------------ END --------------------------------------- public void resetLoggedOperator() { operator=null; getLoggedOperator(); } public Operator getLoggedOperator() { try { if (sessionState.getOpid() != -1) { if (operator == null) { this.operator = (Operator) PersistenceHome.findByPrimaryKey(PlatformConfiguration.defaultOperatorSubclass, sessionState.getOpid()); } return operator; } else return null; } catch (Throwable t) { throw new PlatformRuntimeException(t); } } }