/* * $Id: Block.java,v 1.70.2.1 2007/01/12 19:31:37 idegaweb Exp $ * Created in 2000 by Tryggvi Larusson * * Copyright (C) 2000-2004 Idega Software hf. All Rights Reserved. * * This software is the proprietary information of Idega hf. * Use is subject to license terms. */ package com.idega.presentation; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import com.idega.core.component.data.ICObjectInstance; import com.idega.idegaweb.IWCacheManager; import com.idega.idegaweb.IWMainApplication; import com.idega.idegaweb.IWStyleManager; import com.idega.idegaweb.IWUserContext; import com.idega.idegaweb.block.presentation.Builderaware; import com.idega.presentation.text.Link; import com.idega.presentation.text.Text; /** * This is the base class for all idegaWeb Blocks.<br> * Subclasses of this class should not render themselves out (with the print method), and it is presumed that * their functionality is done with the main() method in old style idegaWeb. * This class has functionality regarding caching and how the main method is processed in JSF. * * Last modified: $Date: 2007/01/12 19:31:37 $ by $Author: idegaweb $ * * @author <a href="mailto:tryggvil@idega.com">Tryggvi Larusson</a> * @version $Revision: 1.70.2.1 $ */ public class Block extends PresentationObjectContainer implements Builderaware { //static variables: private static Map permissionKeyMap = new Hashtable(); public final static String IW_BLOCK_CACHE_KEY = "iw_not_cached"; public static boolean usingNewAcessControlSystem = false; private static final String concatter = "_"; static final String newline = "\n"; //Instance variables: private String cacheKey = null; private String derivedCacheKey = null; private boolean cacheable = false; private long cacheInterval; private int targetObjInst = -1; private int targetObjInstset = -2; private boolean editPermission = false; private boolean debugParameters = false; private String blockWidth = null; public Block() { setDefaultWidth(); setTransient(false); } public String getBundleIdentifier() { return IW_CORE_BUNDLE_IDENTIFIER; } /** * Override to add styles (names) to stylesheet. Add name (String) as key and style (String) as value. */ public Map getStyleNames() { //return IWConstants.getDefaultStyles(); return null; } /** * * @uml.property name="cacheKey" */ public String getCacheKey() { return IW_BLOCK_CACHE_KEY; } public String getLocalizedNameKey() { return "block"; } public String getLocalizedNameValue() { return "Block"; } public String getLocalizedName(IWContext iwc) { return getLocalizedString(getLocalizedNameKey(), getLocalizedNameValue(), iwc); } /////// target features /////// /////// target code begins //////////// public void setTargetObjectInstance(ICObjectInstance instance) { if (instance != null) { this.targetObjInst = instance.getID(); } } public int getTargetObjectInstance() { if (this.targetObjInst > 0) { return this.targetObjInst; } else { return getICObjectInstanceID(); } } public void setAsObjectInstanceTarget(Link link) { if (this.targetObjInst > 0) { link.setTargetObjectInstance(getTargetObjectInstance()); } } public boolean isTarget() { return this.targetObjInstset == this.targetObjInst; } /////// target code ends //////////// ////// debugging parameters ///////// public void setToDebugParameters(boolean debugPrm) { this.debugParameters = debugPrm; } public boolean deleteBlock(int ICObjectInstanceId) { System.err.println("method deleteBlock(int ICObjectInstanceId) not implemented in class " + this.getClass().getName()); return true; } public boolean isAdministrator(IWContext iwc) throws Exception { if (usingNewAcessControlSystem) { return iwc.hasEditPermission(this); } else { return false; //return AccessControl.isAdmin(iwc); } } /** * <H2>Unimplemented</H2> */ public boolean isDeveloper(IWContext iwc) throws Exception { return false; } /** * <H2>Unimplemented</H2> */ public boolean isUser(IWContext iwc) throws Exception { return false; } /** * <H2>Unimplemented</H2> */ public boolean isMemberOf(IWContext iwc, String groupName) throws Exception { return false; } /** * <H2>Unimplemented</H2> */ public boolean hasPermission(String permissionType, PresentationObject obj, IWContext iwc) throws Exception { return iwc.getAccessController().hasPermission(permissionType, obj, iwc); } /* public boolean hasPermission(String permissionType,IWContext iwc)throws Exception{ return hasPermission(permissionType,iwc,this); }*/ public String getModuleName() { return this.getClass().getName(); } /** * Implement in subclasses: */ public void registerPermissionKeys() { } /* protected void registerPermissionKey(String permissionKey,String localizeableKey){ Map m = getPermissionKeyClassMap(); m.put(permissionKey,localizeableKey); } */ protected void registerPermissionKey(String permissionKey) { Map m = getPermissionKeyMap(); if (m.containsKey(getClassName())) { List l = (List) m.get(getClassName()); l.add(permissionKey); } else { List l = new ArrayList(); l.add(permissionKey); m.put(getClassName(), l); } } /** * * @uml.property name="permissionKeyMap" */ private Map getPermissionKeyMap() { return permissionKeyMap; } /* private Map getPermissionKeyClassMap(){ Map m = (Map)getPermissionKeyMap().get(this.getClass()); if(m==null){ m = new Hashtable(); getPermissionKeyMap().put(this.getClass(),m); } return m; } */ public String[] getPermissionKeys() { return getPermissionKeys(getClass()); } public String[] getPermissionKeys(Block obj) { return getPermissionKeys(obj.getClass()); } public String[] getPermissionKeys(Class PresentationObjectClass) { List l = (List) getPermissionKeyMap().get(PresentationObjectClass.getName()); if (l != null) { return (String[]) l.toArray(new String[0]); } return null; } private static long twentyMinutes = 60 * 1000 * 20; /** * * @uml.property name="manager" * @uml.associationEnd multiplicity="(0 1)" */ private IWStyleManager manager; public void setCacheable(String cacheKey) { setCacheable(cacheKey, twentyMinutes); } /**@ todo how do this.cacheKey and setCacheKey work together??**/ public void setCacheable(String cacheKey, long millisecondsInterval) { this.cacheable = true; this.cacheKey = cacheKey; this.cacheInterval = millisecondsInterval; } public void beginCacheing(IWContext iwc, StringBuffer buffer) throws Exception { PrintWriter servletWriter = iwc.getWriter(); iwc.setCacheing(true); PrintWriter writer = new BlockCacheWriter(servletWriter, buffer); if(IWMainApplication.useJSF){ ResponseWriter rWriter = new BlockCacheResponseWriter(iwc.getResponseWriter(),buffer); iwc.setCacheResponseWriter(rWriter); } iwc.setCacheWriter(writer); } public void endCacheing(IWContext iwc, StringBuffer buffer) { iwc.setCacheing(false); IWCacheManager.getInstance(iwc.getIWMainApplication()).setObject(getOriginalCacheKey(), getDerivedCacheKey(), buffer, this.cacheInterval); } public boolean hasEditPermission() { return this.editPermission; } public void _main(IWContext iwc) throws Exception { this.editPermission = iwc.hasEditPermission(this); this.manager = IWStyleManager.getInstance(); if (this.debugParameters) { debugParameters(iwc); } if (iwc.isParameterSet(TARGET_OBJ_INS)) { this.targetObjInstset = Integer.parseInt(iwc.getParameter(TARGET_OBJ_INS)); } if (this.targetObjInst <= 0) { this.targetObjInst = getParentObjectInstanceID(); } if (getStyleNames() != null) { String prefix = getBundle(this.getIWUserContext()).getBundleName(); if (prefix != Builderaware.IW_CORE_BUNDLE_IDENTIFIER) { prefix = prefix.substring(prefix.lastIndexOf(".") + 1) + "_"; } Map styles = getStyleNames(); Iterator iter = styles.keySet().iterator(); while (iter.hasNext()) { String style = (String) iter.next(); if (!this.manager.isStyleSet(prefix + style)) { this.manager.setStyle(prefix + style, (String) styles.get(style)); } } } if (isCacheable(iwc)) { setCacheKey(iwc); if (isCacheValid(iwc)) { } else { super._main(iwc); } } else { super._main(iwc); } } /** * <p> * The default implementation for the print function for Blocks. This method * implements the default Cache (based on IWCacheManager) functionality for caching * the rendered output of this Block.<br> * This implementation is final and therefore can not be overridden. * </p> */ public final void print(IWContext iwc) throws Exception { if (isCacheable(iwc)) { if (isCacheValid(iwc)) { printPreCachedContent(iwc); } else { //the threads will wait locked on the class for this Block synchronized(getClass()){ if(!isCacheValid(iwc)){ //only the first thread should go in here and actually cache: StringBuffer buffer = new StringBuffer(); beginCacheing(iwc, buffer); super.print(iwc); endCacheing(iwc, buffer); } else{ //the second thread and all after that //should just print out the cached content. printPreCachedContent(iwc); } } } } else { super.print(iwc); } } /** * <p> * Prints out the content that has already been cached into a StringBuffer in IWCacheManager. * </p> * @param iwc */ protected void printPreCachedContent(IWContext iwc){ IWCacheManager cacher = IWMainApplication.getIWCacheManager(); StringBuffer buffer = (StringBuffer) cacher.getObject(getDerivedCacheKey()); //iwc.getWriter().print(buffer.toString()); print(buffer.toString()); } public Text getStyleText(String text, String styleName) { return getStyleText(new Text(text),styleName); } public Text getStyleText(Text text, String styleName) { return (Text) setStyle(text,styleName); } public Link getStyleLink(String link, String styleName) { return getStyleLink(new Link(link),styleName); } public Link getStyleLink(Link link, String styleName) { return (Link) setStyle(link,styleName); } public PresentationObject getStyleObject(PresentationObject object, String styleName) { return setStyle(object, styleName); } /** * Gets a prefixed stylename to use for objects, with prefix specific for the bundle used by this block * if the block is in the core bundle, no prefix is added * @param styleName * @return stylename */ private String getStyleName(String styleName, boolean isLink){ if ( getIWUserContext() != null ) { String prefix = getBundle(getIWUserContext()).getBundleName(); if (prefix != Builderaware.IW_CORE_BUNDLE_IDENTIFIER) { prefix = prefix.substring(prefix.lastIndexOf(".") + 1) + "_"; styleName = prefix+styleName; } } if (this.manager != null) { if (!this.manager.isStyleSet(styleName)) { this.manager.setStyle(styleName, ""); } if (autoCreateGlobalHoverStyles() && !this.manager.isStyleSet(styleName + ":hover")) { this.manager.setStyle(styleName + ":hover", ""); } } return styleName; } /** * Gets a prefixed stylename to use for objects, with prefix specific for the bundle used by this block * if the block is in the core bundle, no prefix is added * @param styleName * @return stylename */ public String getStyleName(String styleName){ return getStyleName(styleName, false); } private PresentationObject setStyle(PresentationObject obj, String styleName, boolean isLink) { obj.setStyleClass(getStyleName(styleName, isLink)); return obj; } public PresentationObject setStyle(PresentationObject obj, String styleName) { return setStyle(obj, styleName, false); } private boolean isCacheValid(IWContext iwc) { boolean valid = false; if (this.cacheable) { if (getDerivedCacheKey() != null) { valid = IWCacheManager.getInstance(iwc.getIWMainApplication()).isCacheValid(getDerivedCacheKey()); } } return valid; } /** * * @uml.property name="derivedCacheKey" */ protected String getDerivedCacheKey() { return this.derivedCacheKey; } private String getOriginalCacheKey() { return this.cacheKey; } /** cache specifically for view right and for edit rights**/ private void setCacheKey(IWContext iwc) { this.derivedCacheKey = this.cacheKey + getCacheState(iwc, getCachePrefixString(iwc)); // cacheKey += getCacheState(iwc,getCachePrefixString(iwc)); /**@todo remove debug**/ //debug("cachKey = "+cacheKey); } /** * Default string is currentlocale+hasEditPermission */ protected String getCachePrefixString(IWContext iwc) { int instanceID = this.getICObjectInstanceID(); boolean edit = hasEditPermission(); String locale = iwc.getCurrentLocale().toString(); boolean isSecure = iwc.getRequest().isSecure(); String[] addedPermissionKeys= getPermissionKeys(); String addPerm = ""; if(addedPermissionKeys!=null){ StringWriter permissions = new StringWriter(addedPermissionKeys.length); for (int i = 0; i < addedPermissionKeys.length; i++) { boolean perm = iwc.hasPermission(addedPermissionKeys[i],this); permissions.write(perm?"1":"0"); } addPerm = permissions.toString(); } return (instanceID + locale + edit + isSecure+addPerm); } /** * Override this method if you want to prevent some states from being cached. * This method is called is before getCacheState() * @param iwc * @return */ protected boolean isCacheable(IWContext iwc) { //if(IWMainApplication.useJSF){ //cache temporarily disabled in JSF while cache bug is resolved // return false; //} //else{ return this.cacheable; //} } /** * * @uml.property name="cacheable" */ public void setCacheable(boolean cacheable) { this.cacheable = cacheable; } /** * Override this method for correct caching. The cacheStateprefix will always be <br> * of the form CurrentLocal+edit(boolean) unless you override getCachePrefixString(iwc) <br> * It is better to return a string with that string prefixed to it unless the block output <br> * is the same for every local and edit/view rights. * @return cacheStatePrefix */ protected String getCacheState(IWContext iwc, String cacheStatePrefix) { return cacheStatePrefix; } /** * Override this method to invalidate something other than the current state. * Default: iwc.getApplication().getIWCacheManager().invalidateCache(cacheKey); */ public void invalidateCache(IWContext iwc) { invalidateCache(iwc.getIWMainApplication()); //debug("INVALIDATING : "+getCacheKey(iwc)); } public void invalidateCache(IWMainApplication iwma) { if (getDerivedCacheKey() != null) { IWMainApplication.getIWCacheManager().invalidateCache(getDerivedCacheKey()); } } /** * Default: iwc.getApplication().getIWCacheManager().invalidateCache(cacheKey+suffix); */ public void invalidateCache(IWContext iwc, String suffix) { if (getOriginalCacheKey() != null) { IWMainApplication.getIWCacheManager().invalidateCache(getOriginalCacheKey() + suffix); //debug("INVALIDATING : "+getCacheKey(iwc)+suffix); } } public static Block getCacheableObject(PresentationObject objectToCache, String cacheKey, long millisecondsInterval) { Block obj = new Block(); obj.add(objectToCache); obj.setCacheable(cacheKey, millisecondsInterval); return obj; } public Object clonePermissionChecked(IWUserContext iwc, boolean askForPermission) { if (iwc != null) { //this.setIWApplicationContext(iwc.getApplicationContext()); //this.setIWUserContext(iwc); } if (askForPermission || iwc != null) { if (iwc.hasViewPermission(this)) { return this.clone(); } else { return NULL_CLONE_OBJECT; } } else { return this.clone(); } } public Object clone() { Block obj = (Block) super.clone(); obj.cacheable = this.cacheable; obj.cacheInterval = this.cacheInterval; obj.targetObjInst = this.targetObjInst; if (this.cacheKey != null) { obj.cacheKey = this.cacheKey; } if (this.derivedCacheKey != null) { obj.derivedCacheKey = this.derivedCacheKey; } return obj; } protected boolean autoCreateGlobalHoverStyles() { return false; } /* * Begin Overrided methods from JSF's UIComponent: */ public String getComponentType(){ return "iw.block"; } public void decode(FacesContext fc){ super.decode(fc); } /* (non-Javadoc) * @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, java.lang.Object) */ public void restoreState(FacesContext context, Object state) { Object values[] = (Object[])state; super.restoreState(context, values[0]); this.cacheKey = (String) values[1]; this.derivedCacheKey = (String) values[2]; this.cacheable = ((Boolean) values[3]).booleanValue(); this.cacheInterval = ((Long)values[4]).longValue(); this.targetObjInst = ((Integer)values[5]).intValue(); this.targetObjInstset = ((Integer)values[6]).intValue(); this.editPermission = ((Boolean)values[7]).booleanValue(); this.debugParameters = ((Boolean)values[8]).booleanValue(); this.blockWidth = (String)values[9]; } /* (non-Javadoc) * @see javax.faces.component.StateHolder#saveState(javax.faces.context.FacesContext) */ public Object saveState(FacesContext context) { Object values[] = new Object[10]; values[0] = super.saveState(context); values[1] = this.cacheKey; values[2] = this.derivedCacheKey; values[3] = Boolean.valueOf(this.cacheable); values[4] = new Long(this.cacheInterval); values[5] = new Integer(this.targetObjInst); values[6] = new Integer(this.targetObjInstset); values[7] = Boolean.valueOf(this.editPermission); values[8] = Boolean.valueOf(this.debugParameters); values[9] = this.blockWidth; return values; } /* * End Overrided methods from JSF's UIComponent: */ /* (non-Javadoc) * @see com.idega.presentation.PresentationObject#isContainer() */ public boolean isContainer() { return false; } public void setWidth(String width) { this.blockWidth = width; } public String getWidth() { return this.blockWidth; } protected void setDefaultWidth() { this.blockWidth = Table.HUNDRED_PERCENT; } /** * Returns wheather the "goneThroughMain" variable is reset back to false in the restore phase. */ protected boolean resetGoneThroughMainInRestore(){ return true; } }