package pt.ist.renderers; import org.apache.commons.beanutils.PropertyUtils; import pt.ist.bennu.core.servlets.filters.contentRewrite.GenericChecksumRewriter; import pt.ist.bennu.core.servlets.filters.contentRewrite.RequestRewriter; import pt.ist.renderers.components.HtmlComponent; import pt.ist.renderers.components.HtmlLink; import pt.ist.renderers.components.HtmlLink.Target; import pt.ist.renderers.components.HtmlLinkWithPreprendedComment; import pt.ist.renderers.components.HtmlText; import pt.ist.renderers.components.state.ViewDestination; import pt.ist.renderers.layouts.Layout; import pt.ist.renderers.schemas.Schema; import pt.ist.renderers.utils.RenderKit; import pt.ist.renderers.utils.RenderUtils; /** * This render is used to create a link out of an object. You choose the link * format and some properties can be used to configure the link. You can also * specify the link indirectly by specifing a destination and then defining a * destination with that name in the place were ou use this renderer. * *

* The link body is configured through a sub rendering of the object with the * specified layout and schema. * *

* Example: Jane Doe * * @author cfgi */ public class ObjectLinkRenderer extends OutputRenderer { private boolean useParent; private String linkFormat; private boolean contextRelative; private boolean moduleRelative; private String destination; private String subSchema; private String subLayout; private String key; private String bundle; private String text; private String linkIf; private boolean blankTarget = false; private boolean indentation = false; private boolean hasContext = false; private boolean hasChecksum = true; private String format; public String getFormat() { return this.format; } /** * This allows to specify a presentation format for each object. For more * details about the format syntaxt check the {@see FormatRenderer}. * * @property */ public void setFormat(String format) { this.format = format; } public boolean isBlankTarget() { return blankTarget; } /** * This property allows you to specify if the link opens in a new window or * not. Defaults to false. * * @property */ public void setBlankTarget(boolean blankTarget) { this.blankTarget = blankTarget; } public String getLinkFormat() { return this.linkFormat; } /** * This property allows you to specify the format of the final link. In this * format you can use properties of the object being presented. For example: * * * format="/some/action.do?oid=${id}" * * * @see RenderUtils#getFormattedProperties(String, Object) * @property */ public void setLinkFormat(String linkFormat) { this.linkFormat = linkFormat; } public boolean isContextRelative() { return this.contextRelative; } /** * Indicates that the link specified should be relative to the context of * the application and not to the current module. This also overrides the * module if a destination is specified. * * @property */ public void setContextRelative(boolean contextRelative) { this.contextRelative = contextRelative; } public boolean isModuleRelative() { return this.moduleRelative; } /** * Allows you to choose if the generated link is relative to the current * module. Note that if the link is not context relative then it also isn't * module relative. * * @property */ public void setModuleRelative(boolean moduleRelative) { this.moduleRelative = moduleRelative; } public boolean isUseParent() { return this.useParent; } /** * This property can be used when presenting an object's slot. If this * property is true the object that will be considered when replacing the * properties in the link will be the parent object, that is, the object * that contains the slot being presented. * *

* Off course, if this property is false (the default) the object that will * be considered is the object initialy being presented. * * @property */ public void setUseParent(boolean useParent) { this.useParent = useParent; } public String getDestination() { return this.destination; } /** * This property is an alternative to the use of the * {@link #setLinkFormat(String) linkFormat}. With this property you can * specify the name of the view state destination that will be used. This * property allows you to select the concrete destination in each context * were this configuration is used. * * @property */ public void setDestination(String destination) { this.destination = destination; } public String getText() { return this.text; } /** * The text to appear as the link text. This is a simple alternative to the * full presentation of the object. * * @property */ public void setText(String text) { this.text = text; } public String getKey() { return this.key; } /** * Instead of specifying thr {@link #setText(String) text} property you can * specify a key, with this property, and a bundle with the * {@link #setBundle(String) bundle}. * * @property */ public void setKey(String key) { this.key = key; } public String getBundle() { return this.bundle; } /** * The bundle were the {@link #setKey(String) key} will be fetched. * * @property */ public void setBundle(String bundle) { this.bundle = bundle; } public String getSubLayout() { return this.subLayout; } /** * Specifies the sub layout that will be used for the body of the link, that * is, the object will be presented using the layout specified and the * result of that presentation will be the body of the link. * * @property */ public void setSubLayout(String subLayout) { this.subLayout = subLayout; } public String getSubSchema() { return this.subSchema; } /** * The name of the schema to use in the presentation of the object for the * body of the link. * * @property */ public void setSubSchema(String subSchema) { this.subSchema = subSchema; } public String getLinkIf() { return this.linkIf; } /** * Name of the property to use when determining if we should really do a * link or not. * * @property */ public void setLinkIf(String linkIf) { this.linkIf = linkIf; } /** * Chooses if the generated elements should be indented or not. This can be * usefull when you want to introduce a separator but need to remove extra * spaces. * * @property */ public void setIndentation(boolean indentation) { this.indentation = indentation; } public boolean isIndentation() { return this.indentation; } public boolean getHasContext() { return hasContext; } public void setHasContext(boolean hasContext) { this.hasContext = hasContext; } public boolean getHasChecksum() { return hasChecksum; } public void setHasChecksum(boolean hasChecksum) { this.hasChecksum = hasChecksum; } @Override protected Layout getLayout(Object object, Class type) { return new Layout() { @Override public HtmlComponent createComponent(Object object, Class type) { Object usedObject = getTargetObject(object); if (usedObject == null) { return new HtmlText(); } if (isAllowedToLink(usedObject)) { HtmlLink link = getLink(usedObject); link.setIndented(isIndentation()); String text = getLinkText(); if (text != null) { link.setText(text); } else if (getFormat() != null) { link.setText(RenderUtils.getFormattedProperties(getFormat(), usedObject)); } else { link.setBody(getLinkBody(object)); } if (isBlankTarget()) { link.setTarget(Target.BLANK); } return link; } else { return getLinkBody(object); } } private boolean isAllowedToLink(Object usedObject) { if (getLinkIf() == null) { return true; } else { try { Object object = PropertyUtils.getProperty(usedObject, getLinkIf()); if (object == null) { return true; } else { return (Boolean) object; } } catch (Exception e) { e.printStackTrace(); return false; } } } public HtmlComponent getLinkBody(Object object) { Schema findSchema = RenderKit.getInstance().findSchema(getSubSchema()); return renderValue(object, findSchema, getSubLayout()); } private String getLinkText() { if (getText() != null) { return getText(); } if (getKey() == null) { return null; } return RenderUtils.getResourceString(getBundle(), getKey()); } private HtmlLink getLink(Object usedObject) { HtmlLink link = new HtmlLink(); if (getHasContext()) { link = new HtmlLinkWithPreprendedComment( !getHasChecksum() ? GenericChecksumRewriter.NO_CHECKSUM_PREFIX_HAS_CONTEXT_PREFIX : RequestRewriter.HAS_CONTEXT_PREFIX); } else { link = !getHasChecksum() ? new HtmlLinkWithPreprendedComment(GenericChecksumRewriter.NO_CHECKSUM_PREFIX) : new HtmlLink(); } String url; if (getDestination() != null) { ViewDestination destination = getContext().getViewState().getDestination(getDestination()); if (destination != null) { link.setModule(destination.getModule()); url = destination.getPath(); } else { url = "#"; } } else { if (getLinkFormat() != null) { url = getLinkFormat(); } else { url = "#"; } } link.setUrl(RenderUtils.getFormattedProperties(url, usedObject)); link.setModuleRelative(isModuleRelative()); link.setContextRelative(isContextRelative()); return link; } }; } protected Object getTargetObject(Object object) { if (isUseParent()) { if (getContext().getParentContext() != null) { return getContext().getParentContext().getMetaObject().getObject(); } else { return null; } } else { return object; } } }