From 02790a7b4ab075a43409841d684b5afe43c83f56 Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Tue, 18 Jul 2006 17:35:11 +0000 Subject: [PATCH] . Dashboards impl checkpoint - configurable JSP layouts - configurable "dashlets" (JSP snipets) - page config (de)serialisation per user git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3346 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../web/bean/dashboard/DashboardManager.java | 392 ++++++++++++++++++ .../web/bean/dashboard/PageConfig.java | 283 +++++++++++++ 2 files changed, 675 insertions(+) create mode 100644 source/java/org/alfresco/web/bean/dashboard/DashboardManager.java create mode 100644 source/java/org/alfresco/web/bean/dashboard/PageConfig.java diff --git a/source/java/org/alfresco/web/bean/dashboard/DashboardManager.java b/source/java/org/alfresco/web/bean/dashboard/DashboardManager.java new file mode 100644 index 0000000000..5f3d66c367 --- /dev/null +++ b/source/java/org/alfresco/web/bean/dashboard/DashboardManager.java @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.bean.dashboard; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import javax.faces.context.FacesContext; + +import org.alfresco.config.ConfigService; +import org.alfresco.web.app.Application; +import org.alfresco.web.bean.repository.PreferencesService; +import org.alfresco.web.config.DashboardsConfigElement; +import org.alfresco.web.config.DashboardsConfigElement.DashletDefinition; +import org.alfresco.web.config.DashboardsConfigElement.LayoutDefinition; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Bean that manages the Dashboard framework. + * + * @author Kevin Roast + */ +public final class DashboardManager +{ + private static Log logger = LogFactory.getLog(DashboardManager.class); + + private static final String PREF_DASHBOARD = "dashboard"; + private static final String LAYOUT_DEFAULT = "default"; + private static final String DASHLET_DEFAULT = "getting-started"; + + private static final String JSP_DUMMY = "/jsp/dashboards/dummy.jsp"; + + private PageConfig pageConfig = null; + private DashletRenderingList renderingList = null; + private DashletTitleList titleList = null; + + /** + * @return The layout JSP page for the current My Alfresco dashboard page + */ + public String getLayoutPage() + { + String layout = null; + Page page = getPageConfig().getCurrentPage(); + if (page != null) + { + layout = page.getLayoutDefinition().JSPPage; + } + return layout; + } + + /** + * Helper to init the dashboard for display + */ + public void initDashboard() + { + this.renderingList = null; + } + + /** + * @return JSF List getter to return which dashlets are available for rendering + */ + public List getDashletAvailable() + { + if (this.renderingList == null) + { + this.renderingList = new DashletRenderingList(getPageConfig()); + } + return this.renderingList; + } + + /** + * @return JSF List getter to return dashlet title strings + */ + public List getDashletTitle() + { + if (this.titleList == null) + { + this.titleList = new DashletTitleList(getPageConfig()); + } + return this.titleList; + } + + /** + * Return the JSP for the specified dashlet index + * + * @param index Zero based index from the left most column working top-bottom then left-right + * + * @return JSP page for the dashlet or a blank dummy page if not found + */ + public String getDashletPage(int index) + { + String page = JSP_DUMMY; + DashletDefinition def = getDashletDefinitionByIndex(getPageConfig(), index); + if (def != null) + { + page = def.JSPPage; + } + return page; + } + + /** + * Helper to get the DashDefinition as the zero based index, working from the left most column + * top-bottom then working left-right. + * + * @param index Zero based index from the left most column working top-bottom then left-right + * + * @return DashletDefinition if found or null if no dashlet at the specified index + */ + private static DashletDefinition getDashletDefinitionByIndex(PageConfig config, int index) + { + DashletDefinition def = null; + + LayoutDefinition layoutDef = config.getCurrentPage().getLayoutDefinition(); + List columns = config.getCurrentPage().getColumns(); + int columnCount = columns.size(); + int selectedColumn = index / layoutDef.ColumnLength; + if (selectedColumn < columnCount) + { + List dashlets = columns.get(selectedColumn).getDashlets(); + if (index % layoutDef.ColumnLength < dashlets.size()) + { + def = dashlets.get(index % layoutDef.ColumnLength); + } + } + if (logger.isDebugEnabled()) + logger.debug("Searching for dashlet at index: " + index + + " and found " + (def != null ? def.JSPPage : null)); + + return def; + } + + /** + * @return the PageConfig for the current My Alfresco dashboard page + */ + private PageConfig getPageConfig() + { + if (this.pageConfig == null) + { + PageConfig pageConfig; + + DashboardsConfigElement config = getDashboardConfig(); + + // read the config for this user from the Preferences + String xml = (String)PreferencesService.getPreferences().getValue(PREF_DASHBOARD); + if (xml != null && xml.length() != 0) + { + if (logger.isDebugEnabled()) + logger.debug("PageConfig found: " + xml); + + // process the XML config and convert into a PageConfig object + pageConfig = new PageConfig(); + pageConfig.fromXML(config, xml); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("No PageConfig found, creating default instance."); + + // create default config for the first access for a user + pageConfig = new PageConfig(); + LayoutDefinition layout = config.getLayoutDefinition(LAYOUT_DEFAULT); + if (layout != null) + { + Page page = new Page("default", layout); + Column defaultColumn = new Column(); + DashletDefinition dashlet = config.getDashletDefinition(DASHLET_DEFAULT); + if (dashlet != null) + { + defaultColumn.addDashlet(dashlet); + page.addColumn(defaultColumn); + pageConfig.addPage(page); + } + } + + // persist the config for this user + //PreferencesService.getPreferences().setValue(PREF_DASHBOARD, pageConfig.toXML()); + } + + this.pageConfig = pageConfig; + } + + return this.pageConfig; + } + + /** + * @return The externally configured WebClient config element for the Dashboards + */ + private static DashboardsConfigElement getDashboardConfig() + { + ConfigService service = Application.getConfigService(FacesContext.getCurrentInstance()); + DashboardsConfigElement config = (DashboardsConfigElement)service.getConfig("Dashboards").getConfigElement( + DashboardsConfigElement.CONFIG_ELEMENT_ID); + return config; + } + + + /** + * Dashlet rendering list. + * + * Returns true from the get() method if the specified dashlet is available for rendering. + */ + private static class DashletRenderingList extends JSFHelperList + { + PageConfig config; + + public DashletRenderingList(PageConfig config) + { + this.config = config; + } + + /** + * @see java.util.List#get(int) + */ + public Object get(int index) + { + return getDashletDefinitionByIndex(config, index) != null; + } + } + + /** + * Dashlet title list. + * + * Returns the title string from the get() method if the specified dashlet is available. + */ + private static class DashletTitleList extends JSFHelperList + { + PageConfig config; + + public DashletTitleList(PageConfig config) + { + this.config = config; + } + + /** + * @see java.util.List#get(int) + */ + public Object get(int index) + { + String result = ""; + + DashletDefinition def = getDashletDefinitionByIndex(config, index); + if (def != null) + { + if (def.LabelId != null) + { + result = Application.getMessage(FacesContext.getCurrentInstance(), def.LabelId); + } + else if (def.Label != null) + { + result = def.Label; + } + } + + return result; + } + } + + /** + * Helper class that implements a dummy List contract for use by JSF List getter methods + */ + private static abstract class JSFHelperList implements List + { + // + // Satisfy List interface contract + // + + public void add(int arg0, Object arg1) + { + } + + public boolean add(Object arg0) + { + return false; + } + + public boolean addAll(Collection arg0) + { + return false; + } + + public boolean addAll(int arg0, Collection arg1) + { + return false; + } + + public void clear() + { + } + + public boolean contains(Object arg0) + { + return false; + } + + public boolean containsAll(Collection arg0) + { + return false; + } + + public int indexOf(Object arg0) + { + return 0; + } + + public boolean isEmpty() + { + return false; + } + + public Iterator iterator() + { + return null; + } + + public int lastIndexOf(Object arg0) + { + return 0; + } + + public ListIterator listIterator() + { + return null; + } + + public ListIterator listIterator(int arg0) + { + return null; + } + + public Object remove(int arg0) + { + return null; + } + + public boolean remove(Object arg0) + { + return false; + } + + public boolean removeAll(Collection arg0) + { + return false; + } + + public boolean retainAll(Collection arg0) + { + return false; + } + + public Object set(int arg0, Object arg1) + { + return null; + } + + public int size() + { + return 0; + } + + public List subList(int arg0, int arg1) + { + return null; + } + + public Object[] toArray() + { + return null; + } + + public Object[] toArray(Object[] arg0) + { + return null; + } + } +} diff --git a/source/java/org/alfresco/web/bean/dashboard/PageConfig.java b/source/java/org/alfresco/web/bean/dashboard/PageConfig.java new file mode 100644 index 0000000000..3cd96be9b9 --- /dev/null +++ b/source/java/org/alfresco/web/bean/dashboard/PageConfig.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.bean.dashboard; + +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.web.config.DashboardsConfigElement; +import org.alfresco.web.config.DashboardsConfigElement.DashletDefinition; +import org.alfresco.web.config.DashboardsConfigElement.LayoutDefinition; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; + +/** + * Describes the config for the Pages in a user Dashboard. + * Multiple Pages are supported. + * + * @author Kevin Roast + */ +final class PageConfig +{ + private static Log logger = LogFactory.getLog(DashboardManager.class); + + private static final String ELEMENT_DASHBOARD = "dashboard"; + private static final String ELEMENT_PAGE = "page"; + private static final String ELEMENT_COLUMN = "column"; + private static final String ELEMENT_DASHLET = "dashlet"; + private static final String ATTR_ID = "id"; + private static final String ATTR_LAYOUTID = "layout-id"; + private static final String ATTR_REFID = "idref"; + + private List pages = new ArrayList(4); + private int currentPageIndex = 0; + + public Page getCurrentPage() + { + if (currentPageIndex < pages.size()) + { + return pages.get(currentPageIndex); + } + else + { + return null; + } + } + + public void addPage(Page page) + { + pages.add(page); + } + + public Page getPage(String pageId) + { + Page foundPage = null; + for (Page page : pages) + { + if (page.getId().equals(pageId)) + { + foundPage = page; + break; + } + } + return foundPage; + } + + /** + * Convert this config to an XML definition which can be serialized. + * Example: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * @return XML for this config + */ + public String toXML() + { + try + { + Document doc = DocumentHelper.createDocument(); + + Element root = doc.addElement(ELEMENT_DASHBOARD); + for (Page page : pages) + { + Element pageElement = root.addElement(ELEMENT_PAGE); + pageElement.addAttribute(ATTR_ID, page.getId()); + pageElement.addAttribute(ATTR_LAYOUTID, page.getLayoutDefinition().Id); + for (Column column : page.getColumns()) + { + Element columnElement = pageElement.addElement(ELEMENT_COLUMN); + for (DashletDefinition dashletDef : column.getDashlets()) + { + columnElement.addElement(ELEMENT_DASHLET).addAttribute(ATTR_REFID, dashletDef.Id); + } + } + } + + StringWriter out = new StringWriter(512); + XMLWriter writer = new XMLWriter(OutputFormat.createPrettyPrint()); + writer.setWriter(out); + writer.write(doc); + + return out.toString(); + } + catch (Throwable err) + { + throw new AlfrescoRuntimeException("Unable to serialize Dashboard PageConfig to XML: " + err.getMessage(), err); + } + } + + @Override + public String toString() + { + return toXML(); + } + + /** + * Deserialise this PageConfig instance from the specified XML stream. + * + * @param xml + */ + public void fromXML(DashboardsConfigElement config, String xml) + { + try + { + SAXReader reader = new SAXReader(); + Document document = reader.read(new StringReader(xml)); + Element rootElement = document.getRootElement(); + + // walk the pages found in xml + Iterator itrPages = rootElement.elementIterator(ELEMENT_PAGE); + while (itrPages.hasNext()) + { + Element pageElement = (Element)itrPages.next(); + String layoutId = pageElement.attributeValue(ATTR_LAYOUTID); + LayoutDefinition layoutDef = config.getLayoutDefinition(layoutId); + if (layoutDef != null) + { + // found the layout now build the page and read the columns + Page page = new Page(pageElement.attributeValue(ATTR_ID), layoutDef); + Iterator itrColumns = pageElement.elementIterator(ELEMENT_COLUMN); + while (itrColumns.hasNext()) + { + Column column = new Column(); + + // read and resolve the dashlet definitions for this column + Element columnElement = (Element)itrColumns.next(); + Iterator itrDashlets = columnElement.elementIterator(ELEMENT_DASHLET); + while (itrDashlets.hasNext()) + { + String dashletId = ((Element)itrDashlets.next()).attributeValue(ATTR_REFID); + DashletDefinition dashletDef = config.getDashletDefinition(dashletId); + if (dashletDef != null) + { + column.addDashlet(dashletDef); + } + else if (logger.isWarnEnabled()) + { + logger.warn("Failed to resolve Dashboard Dashlet Definition ID: " + dashletId); + } + } + + // add the column of dashlets to the page + page.addColumn(column); + } + + // add the page to this config instance + this.addPage(page); + } + else if (logger.isWarnEnabled()) + { + logger.warn("Failed to resolve Dashboard Layout Definition ID: " + layoutId); + } + } + } + catch (DocumentException docErr) + { + // if we cannot parse, then we simply revert to default + } + } +} + +/** + * Simple class to represent a Page in a Dashboard. + * Each Page has a Layout associated with it, and a number of Column definitions. + */ +final class Page +{ + private String id; + private LayoutDefinition layoutDef; + private List columns = new ArrayList(4); + + public Page(String id, LayoutDefinition layout) + { + if (id == null || id.length() == 0) + { + throw new IllegalArgumentException("ID for a Dashboard Page is mandatory."); + } + if (layout == null) + { + throw new IllegalArgumentException("Layout for a Dashboard Page is mandatory."); + } + this.id = id; + this.layoutDef = layout; + } + + public String getId() + { + return this.id; + } + + public LayoutDefinition getLayoutDefinition() + { + return this.layoutDef; + } + + public void addColumn(Column column) + { + this.columns.add(column); + } + + public List getColumns() + { + return this.columns; + } +} + +/** + * Simple class representing a single Column in a dashboard Page. + * Each column contains a list of Dashlet definitions. + */ +final class Column +{ + private List dashlets = new ArrayList(4); + + public void addDashlet(DashletDefinition dashlet) + { + dashlets.add(dashlet); + } + + public List getDashlets() + { + return this.dashlets; + } +}