/* * Created on Oct 19, 2004 */ package com.openedit.page; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openedit.profile.UserProfile; import com.openedit.OpenEditException; import com.openedit.WebPageRequest; import com.openedit.generators.Output; import com.openedit.page.manage.PageManager; import com.openedit.servlet.OpenEditEngine; import com.openedit.users.User; import com.openedit.util.PathUtilities; /** * @author Matthew Avery, mavery@einnovation.com */ public class PageStreamer { private static final Log log = LogFactory.getLog(PageStreamer.class); protected OpenEditEngine fieldEngine; protected Output fieldOutput; protected WebPageRequest fieldWebPageRequest; protected Map fieldWebPageRequestedCount; protected List fieldChildContentList; protected int fieldMaxLoop = 10000; protected boolean fieldDebug = false; public PageStreamer() { //log.debug("Created streamer"); } /** * This is called only once * We need to exec all the page actions ahead of time * And check the read permissions ahead of time * Then we can do the rendering * @throws OpenEditException */ public void render() throws OpenEditException { Page page = getWebPageRequest().getPage(); boolean runlayout = page.isHtml(); if( !runlayout) { runlayout = Boolean.parseBoolean( page.getProperty("forcelayout") ); } if (runlayout) { getChildContentList().add(getWebPageRequest().getContentPage() ); //allow someone to programatically override the top level inner layout String override = (String)getWebPageRequest().getPageValue(PageRequestKeys.INNERLAYOUTOVERRIDE); if( override != null) { if( !override.equals(Page.BLANK_LAYOUT)) { Page il = getPage(override); addInnerLayout( il); } } else { addInnerLayout( getWebPageRequest().getContentPage()); } //handle layout String layout = getLayout(); if ( layout != null ) { Page layoutPage = getPage(layout); getChildContentList().add(0,layoutPage); } User user = getWebPageRequest().getUser(); if( user != null) { if( "debug".equals(user.getProperty("oe.edit.mode"))) { setDebug(true); } } if( getChildContentList().size() > 1) { //This number starts at the content page and ends in the middle of the layouts String maxlevels = getWebPageRequest().getRequestParameter("oemaxlevel"); if( maxlevels == null) { maxlevels = getWebPageRequest().getContentProperty("oemaxlevel"); } if( maxlevels != null) { int cut = Integer.parseInt(maxlevels); List toCut = getChildContentList(); if( cut < toCut.size()) { toCut = toCut.subList(toCut.size() - cut, toCut.size()); fieldChildContentList = toCut; } } } if( getChildContentList().size() > 1) { //This number starts in the middle of the layout list and ends at the content String maxlevels = getWebPageRequest().getRequestParameter("oemaxlayout"); if( maxlevels == null) { maxlevels = getWebPageRequest().getContentProperty("oemaxlayout"); } if( maxlevels != null) { int cut = Integer.parseInt(maxlevels); List toCut = getChildContentList(); if( cut < toCut.size()) { toCut = toCut.subList(cut, toCut.size()); fieldChildContentList = toCut; } } } String cancel = getWebPageRequest().getPage().getPageSettings().getPropertyValueFixed("cancelinnerlayout"); if( cancel != null) { List toCut = getChildContentList(); for (int i = 0; i < toCut.size(); i++) { Page path = (Page) toCut.get(i); if( path.getPath().equals(cancel)) { toCut.remove(i); break; } } } includeContent(); } else { //CSS files. Binary WebPageRequest request = getWebPageRequest(); Page torender = getPageManager().getPage(page, getWebPageRequest() ); if ( torender != page ) //This could be a draft version { request = getWebPageRequest().copy(torender); getEngine().executePageActions(request); } torender.generate(request, getOutput()); } } protected void addInnerLayout(Page inContentPage) throws OpenEditException { // log.info("Adding " + inContentPage); String innerlayout = inContentPage.findInnerLayout(); if ( innerlayout != null) { UserProfile profile = getWebPageRequest().getUserProfile(); if( profile != null) { innerlayout = profile.replaceUserVariable(innerlayout); } if( !inContentPage.getPath().equalsIgnoreCase(innerlayout)) { //The contentpage has an inner layout set that is not itself Page il = getPageManager().getPage(innerlayout,getWebPageRequest().getUser() != null); if( !getChildContentList().contains(il)) { //It is not in the list so we add it if( getChildContentList().size() < getMaxLoop() ) { getChildContentList().add(0,il); addInnerLayout(il); } } else { //Special case: It is aleady in the list so we try again using the parent layout //We might have a directory that has two layouts inside it. String parentpath = PathUtilities.extractDirectoryPath(il.getParentPath()); if( !parentpath.equals("")) { Page parent = getPageManager().getPage(parentpath,getWebPageRequest().getUser() != null); if( parent.hasInnerLayout()) { il = getPageManager().getPage(parent.getInnerLayout(),true); if( !getChildContentList().contains(il) ) //If we find two in a row we stop looking { addInnerLayout(parent); } } } } } } //log.info("Found " + inContentPage.getPath() + " layouts: " + getChildContentList()); } protected void renderLayout() throws OpenEditException { Page inLayout = getEngine().getPageManager().getPage(getLayout(),getWebPageRequest().getUser() != null); if (!inLayout.exists()) { getWebPageRequest().putPageValue("missingLayoutPage", inLayout.getPath()); inLayout = getPage("/layoutnotfound.html"); if (!inLayout.exists()) { inLayout = getPage("/openedit/layoutnotfound.html"); } } include(inLayout); } /** * @deprecated use includeContent() * @throws OpenEditException */ public void streamContent() throws OpenEditException { includeContent(); } /** * @deprecated use includeContent() * @throws OpenEditException */ public void renderContent() throws OpenEditException { includeContent(); } public void includeContent() throws OpenEditException { //if I am being called from an inner layout make sure I am at the top first if ( getChildContentList().size() == 0) { //throw new OpenEditException("Ran out of content on " + getWebPageRequest().getPath()); //stream(getPage()); return; } Page topChild = (Page)getChildContentList().remove(0); include( topChild , getWebPageRequest() ); } public void include(Page inPage) throws OpenEditException { include( inPage, getWebPageRequest() ); } /** * Allows a page to be streamed that uses this request as the parent request */ public void include(Page inPage, WebPageRequest inContext) throws OpenEditException { int hitcount = incrementWebPageRequestedCount(inPage); //This is used when viewing a layout page directly (i.e. /layout.html) if (hitcount >= getMaxLoop()) { //ok its an infinite loop throw new OpenEditException( "Page loop detected calling " + inPage.getPath() + "more than " + getMaxLoop() + " times."); } //This is trickly to understand. The contents actions have already been run. Now we either //run the actions or if its the content page those actions have already been run Page torender = null; WebPageRequest request = inContext; if (inPage == inContext.getContentPage()) { torender = getPageManager().getPage(inPage, request ); if ( torender != inPage ) //This could be a draft version { request = inContext.copy(torender); getEngine().executePageActions(request); } } else { //these are the included pages ie. /sidebar.html that may have their own actions request = inContext.copy(inPage); // Ensure the FILE_PATH variable has the correct value for this streamed page. request.putPageValue(PageRequestKeys.FILE_PATH, inPage.getDirectory()); //This is legacy from OE 4.0 can be deleted anytime torender = getPageManager().getPage(inPage, request ); if ( torender != inPage) //This could be a draft version { request = request.copy(torender); } if (!request.hasRedirected() ) { getEngine().executePageActions(request); } } request.putPageValue("originalPage", inPage); torender.generate(request, getOutput() ); } public void include(String inPath, WebPageRequest inReq) throws OpenEditException { String[] parts = inPath.split("[?]"); String fullPath = PathUtilities.resolveRelativePath(parts[0], getWebPageRequest().getContentPage() .getPath()); boolean canedit = false; User user = getWebPageRequest().getUser(); if( user != null ) { String prop = (String)user.get("showeditor"); canedit = Boolean.parseBoolean(prop); } Page page = getEngine().getPageManager().getPage(fullPath,canedit); if (parts.length > 1) { Map arguments = PathUtilities.extractArguments(parts[1]); for (Iterator iterator = arguments.keySet().iterator(); iterator.hasNext();) { String param = (String)iterator.next(); inReq.setRequestParameter(param, (String[])arguments.get(param)); } } include(page, inReq); } public void include(String inPath) throws OpenEditException { include( inPath, getWebPageRequest()); } /** * Use include * @deprecated */ public void stream(Page inPage) throws OpenEditException { include( inPage); } /** * Use include * @deprecated */ public void stream(Page inPage, WebPageRequest inContext) throws OpenEditException { include( inPage, inContext); } /** * Use include * @deprecated */ public void stream(String inPath, WebPageRequest inReq) throws OpenEditException { include( inPath, inReq); } /** * Use include * @deprecated */ public void stream(String inPath) throws OpenEditException { include( inPath ); } public Map getWebPageRequestedCount() { if (fieldWebPageRequestedCount == null) { fieldWebPageRequestedCount = new HashMap(); } return fieldWebPageRequestedCount; } protected int incrementWebPageRequestedCount(Page inPage) { Integer count = (Integer) getWebPageRequestedCount().get(inPage); int hitcount = 0; if (count != null) { hitcount = count.intValue() + 1; } getWebPageRequestedCount().put(inPage, new Integer(hitcount)); return hitcount; } public boolean doesExist(String inPath) throws OpenEditException { if (inPath == null) { return false; } return loadRelativePath(inPath).exists(); } protected Page loadRelativePath(String inPath) throws OpenEditException { String fullPath = PathUtilities.buildRelative(inPath, getWebPageRequest().getContentPage().getPath()); return getPage(fullPath); } public Page getPage(String inPath) throws OpenEditException { return getPageManager().getPage(inPath, getWebPageRequest().getUser() != null); } public PageManager getPageManager() { return getEngine().getPageManager(); } public OpenEditEngine getEngine() { return fieldEngine; } public void setEngine(OpenEditEngine engine) { fieldEngine = engine; } public WebPageRequest getWebPageRequest() { return fieldWebPageRequest; } public void setWebPageRequest(WebPageRequest WebPageRequest) { fieldWebPageRequest = WebPageRequest; } public void forward(String path, WebPageRequest inReq) throws OpenEditException { //if this is the error page then we can get into an infinite loop //WebPageRequest WebPageRequest = getWebPageRequest().copy(); //WebPageRequest.setPage( getPage( path ) ); //getEngine().render( WebPageRequest ); Page original = inReq.getPage(); Page page = getPage(path); //remove layout overrides WebPageRequest req = getWebPageRequest(); req.removePageValue(PageRequestKeys.INNERLAYOUTOVERRIDE); req.removePageValue(PageRequestKeys.LAYOUTOVERRIDE); if( req.getContentPage().getPath().equals(inReq.getPage().getPath())) //are we rendeing the content page? { req.putProtectedPageValue(PageRequestKeys.CONTENT,page); } req.putProtectedPageValue(PageRequestKeys.PAGE,page); req.putPageValue("forwardpage", original); getEngine().getModuleManager().executePathActions(page, req); getEngine().getModuleManager().executePageActions( page,req ); inReq.setHasForwarded(true); //Now it continues to render as normal but with alternative content. //Does not support custom layouts } public PageStreamer copy() { PageStreamer streamer = new PageStreamer(); streamer.setEngine(getEngine()); streamer.fieldChildContentList = getChildContentList(); streamer.setWebPageRequest(getWebPageRequest()); streamer.setOutput(getOutput()); return streamer; } protected String getLayout() { String override = (String) getWebPageRequest().getPageValue("layoutoverride"); if (override != null) { if (override.equals(Page.BLANK_LAYOUT)) { return null; } return override; } Page page = getWebPageRequest().getPage(); if (page.hasLayout()) { String layout = page.getLayout(); layout = page.getPageSettings().replaceProperty(layout); return layout; } return null; } public List getChildContentList() { if ( fieldChildContentList == null) { fieldChildContentList = new ArrayList(); } return fieldChildContentList; } public Output getOutput() { return fieldOutput; } public void setOutput(Output inOutput) { fieldOutput = inOutput; } public boolean canView(String inPath) throws OpenEditException { Page linkpage = getPageManager().getPage(inPath,getWebPageRequest().getUser() != null); if (linkpage.exists() || Boolean.parseBoolean( linkpage.getProperty("virtual"))) { Permission filter = linkpage.getPermission("view"); if( filter != null) { WebPageRequest req = getWebPageRequest().copy(linkpage); boolean value= filter.passes( req ); return value; } return true; } return false; } public boolean canDo(String inDo, String inPath) throws OpenEditException { Page linkpage = getPageManager().getPage(inPath); Permission filter = linkpage.getPermission(inDo); if( filter != null) { WebPageRequest req = getWebPageRequest().copy(linkpage); boolean value= filter.passes( req ); return value; } return true; } public WebPageRequest canDoPermissions(String inPath) throws OpenEditException { Page linkpage = getPageManager().getPage(inPath,getWebPageRequest().getUser() != null); WebPageRequest request = getWebPageRequest().copy(linkpage); request.putPageValue(PageRequestKeys.CONTENT, linkpage); getEngine().getModuleManager().execute("Admin.loadPermissions",request); return request; } public boolean canEdit(String inPath) throws OpenEditException { if (inPath == null) { return false; } boolean value = canDo("edit",inPath); if(value == false) { User user = getWebPageRequest().getUser(); if( user != null) { value = user.hasPermission("oe.filemanager.editall"); } } return value; } public int getMaxLoop() { return fieldMaxLoop; } public void setMaxLoop(int inMaxLoop) { fieldMaxLoop = inMaxLoop; } public boolean isDebug() { return fieldDebug; } public void setDebug(boolean inDebug) { fieldDebug = inDebug; } }