diff --git a/ccm-cms/src/com/arsdigita/cms/ui/authoring/GenericArticleBody.java b/ccm-cms/src/com/arsdigita/cms/ui/authoring/GenericArticleBody.java index f9619d686..ef075f410 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/authoring/GenericArticleBody.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/authoring/GenericArticleBody.java @@ -18,7 +18,6 @@ */ package com.arsdigita.cms.ui.authoring; - import com.arsdigita.bebop.Component; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.RequestLocal; @@ -34,14 +33,12 @@ import com.arsdigita.cms.util.GlobalizationUtil; import com.arsdigita.domain.DomainObject; import com.arsdigita.util.Assert; - /** - * Displays the current text body of the article and allows the user - * to edit it, by uploading a file or entering text in a textbox. + * Displays the current text body of the article and allows the user to edit it, by uploading a file + * or entering text in a textbox. * - * The {@link com.arsdigita.bebop.PropertySheet} class is often used - * as the display component in the default authoring kit steps of - * this class. + * The {@link com.arsdigita.bebop.PropertySheet} class is often used as the display component in the + * default authoring kit steps of this class. * * @author Stanislav Freidin (sfreidin@arsdigita.com) * @version $Id: GenericArticleBody.java 1949 2009-06-25 08:30:50Z terry $ @@ -54,12 +51,11 @@ public class GenericArticleBody extends TextAssetBody { /** * Construct a new GenericArticleBody component * - * @param itemModel The {@link ItemSelectionModel} which will - * be responsible for loading the current item + * @param itemModel The {@link ItemSelectionModel} which will be responsible for loading the + * current item * - * @param parent The parent wizard which contains the form. The form - * may use the wizard's methods, such as stepForward and stepBack, - * in its process listener. + * @param parent The parent wizard which contains the form. The form may use the wizard's + * methods, such as stepForward and stepBack, in its process listener. */ public GenericArticleBody(ItemSelectionModel itemModel, AuthoringKitWizard parent) { super(new ItemAssetModel(itemModel)); @@ -69,17 +65,18 @@ public class GenericArticleBody extends TextAssetBody { // Rest the component when it is hidden parent.getList().addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) { - PageState state = e.getPageState(); - reset(state); - } - }); + public void actionPerformed(ActionEvent e) { + PageState state = e.getPageState(); + reset(state); + } + + }); // Set the right component access on the forms Component f = getComponent(FILE_UPLOAD); if (f != null) { - setComponentAccess(FILE_UPLOAD, - new WorkflowLockedComponentAccess(f, itemModel)); + setComponentAccess(FILE_UPLOAD, + new WorkflowLockedComponentAccess(f, itemModel)); } Component t = getComponent(TEXT_ENTRY); setComponentAccess(TEXT_ENTRY, @@ -87,9 +84,10 @@ public class GenericArticleBody extends TextAssetBody { } /** - * Adds the options for the mime type select widget of - * GenericArticleForm and sets the default mime type. - **/ + * Adds the options for the mime type select widget of GenericArticleForm and sets + * the default mime type. + * + */ @Override protected void setMimeTypeOptions(SingleSelect mimeSelect) { mimeSelect.addOption(new Option("text/html", "HTML Text")); @@ -100,6 +98,7 @@ public class GenericArticleBody extends TextAssetBody { * Create a new text asset and associate it with the current item * * @param s the current page state + * * @return a valid TextAsset */ protected TextAsset createTextAsset(PageState s) { @@ -109,7 +108,7 @@ public class GenericArticleBody extends TextAssetBody { final int idLen = item.getID().toString().length(); final int len = nameLen + 6 + idLen; if (len < 200) { - t.setName(item.getName() + "_text_" + item.getID()); + t.setName(item.getName() + "_text_" + item.getID()); } else { t.setName(item.getName().substring(0, 200 - (len - 200)) + "_text_" + item.getID()); } @@ -120,8 +119,8 @@ public class GenericArticleBody extends TextAssetBody { } /** - * Set additional parameters of a brand new text asset, such as the - * parent ID, after the asset has been successfully uploaded + * Set additional parameters of a brand new text asset, such as the parent ID, after the asset + * has been successfully uploaded * * @param s the current page state * @param a the new TextAsset @@ -131,7 +130,7 @@ public class GenericArticleBody extends TextAssetBody { Assert.exists(t); // no need - cg. Text doesn't need a security context, // and ownership of text is recorded in text_pages - + // a.setParent(t); t.setTextAsset(a); a.save(); @@ -142,12 +141,11 @@ public class GenericArticleBody extends TextAssetBody { * Get the current GenericArticle */ protected GenericArticle getGenericArticle(PageState s) { - return (GenericArticle)m_itemModel.getSelectedObject(s); + return (GenericArticle) m_itemModel.getSelectedObject(s); } /** - * An ACSObjectSelectionModel that selects the current text asset for - * the text page + * An ACSObjectSelectionModel that selects the current text asset for the text page */ private static class ItemAssetModel extends ItemSelectionModel { @@ -158,25 +156,26 @@ public class GenericArticleBody extends TextAssetBody { m_asset = new RequestLocal() { @Override - protected Object initialValue(PageState s) { - GenericArticle t = (GenericArticle) - ((ItemSelectionModel)getSingleSelectionModel()) - .getSelectedObject(s); - Assert.exists(t); - return t.getTextAsset(); - } - }; + protected Object initialValue(PageState s) { + GenericArticle t + = (GenericArticle) ((ItemSelectionModel) getSingleSelectionModel()). + getSelectedObject(s); + Assert.exists(t); + return t.getTextAsset(); + } + + }; } @Override public Object getSelectedKey(PageState s) { - TextAsset a = (TextAsset)getSelectedObject(s); + TextAsset a = (TextAsset) getSelectedObject(s); return (a == null) ? null : a.getID(); } @Override public DomainObject getSelectedObject(PageState s) { - return (DomainObject)m_asset.get(s); + return (DomainObject) m_asset.get(s); } @Override @@ -186,13 +185,15 @@ public class GenericArticleBody extends TextAssetBody { @Override public void setSelectedKey(PageState s, Object key) { - throw new UnsupportedOperationException( (String) GlobalizationUtil.globalize("cms.ui.authoring.not_implemented").localize()); + throw new UnsupportedOperationException((String) GlobalizationUtil.globalize( + "cms.ui.authoring.not_implemented").localize()); } @Override public boolean isSelected(PageState s) { return (getSelectedObject(s) != null); } + } } diff --git a/ccm-core/src/ccm-core.config b/ccm-core/src/ccm-core.config index c58377fad..4af189723 100755 --- a/ccm-core/src/ccm-core.config +++ b/ccm-core/src/ccm-core.config @@ -34,6 +34,8 @@ storage="ccm-core/templating.properties"/> + The top-level container for all Bebop components and containers.

+ *

+ * The top-level container for all Bebop components and containers.

* - *
  • Holds references to the components of a page.
  • Provides - * methods for servicing requests and for notifying other components that a - * request for this page has been received through - * {@link ActionListener ActionListeners}.
  • + *
    • Holds references to the components of a page.
    • Provides methods for servicing + * requests and for notifying other components that a request for this page has been received + * through {@link ActionListener ActionListeners}.
    • * - *
    • Tracks request parameters for stateful components, such as tabbed panes - * and sortable tables.

    A typical - * Page may be created as follows: null

    
    + * 
  • Tracks request parameters for stateful components, such as tabbed panes and sortable + * tables.
+ *

+ * A typical Page may be created as follows: null


  * Page p = new Page("Hello World");
  * p.add(new Label("Hello World");
  * p.lock();
@@ -75,624 +76,604 @@ import org.apache.log4j.Logger;
  */
 public class Page extends BlockStylable implements Container {
 
-	/**
-	 * Class specific logger instance.
-	 */
-	private static final Logger s_log = Logger.getLogger(Page.class);
-	/**
-	 * The delimiter character for components naming
-	 */
-	private static final String DELIMITER = ".";
-	/**
-	 * The prefix that gets prepended to all state variables. Components
-	 * must not use variables starting with this prefix. This guarantees
-	 * that the page state and variables individual components wish to pass
-	 * do not interfere with each other.
-	 */
-	private static final String COMPONENT_PREFIX = "bbp" + DELIMITER;
-	private static final String INTERNAL = COMPONENT_PREFIX;
-	/**
-	 * The name of the special parameter that indicates which component has
-	 * been selected.
-	 */
-	static final String SELECTED = INTERNAL + "s";
-	static final String CONTROL_EVENT = INTERNAL + "e";
-	static final String CONTROL_VALUE = INTERNAL + "v";
-	static final Collection CONTROL_EVENT_KEYS;
+    /**
+     * Class specific logger instance.
+     */
+    private static final Logger s_log = Logger.getLogger(Page.class);
+    /**
+     * The delimiter character for components naming
+     */
+    private static final String DELIMITER = ".";
+    /**
+     * The prefix that gets prepended to all state variables. Components must not use variables
+     * starting with this prefix. This guarantees that the page state and variables individual
+     * components wish to pass do not interfere with each other.
+     */
+    private static final String COMPONENT_PREFIX = "bbp" + DELIMITER;
+    private static final String INTERNAL = COMPONENT_PREFIX;
+    /**
+     * The name of the special parameter that indicates which component has been selected.
+     */
+    static final String SELECTED = INTERNAL + "s";
+    static final String CONTROL_EVENT = INTERNAL + "e";
+    static final String CONTROL_VALUE = INTERNAL + "v";
+    static final Collection CONTROL_EVENT_KEYS;
 
-	static {
-		s_log.debug("Static initalizer is starting...");
-		CONTROL_EVENT_KEYS = new ArrayList(3);
-		CONTROL_EVENT_KEYS.add(SELECTED);
-		CONTROL_EVENT_KEYS.add(CONTROL_EVENT);
-		CONTROL_EVENT_KEYS.add(CONTROL_VALUE);
-		s_log.debug("Static initalizer finished.");
-	}
-	/**
-	 * The name of the request parameter used for the visibility state of
-	 * components stored in m_invisible.
-	 */
-	static final String INVISIBLE = INTERNAL + "i";
-	/**
-	 * Map of stateful components (id --> Component) SortedMap used because
-	 * component based hash for page is based on concatenation of component
-	 * ids, and so need to guarantee that they are returned in the same
-	 * order for the same page - cg.
-	 */
-	private SortedMap m_componentMap;
-	private List m_components;
-	/**
-	 * Map of component -> owned parameter collection
-	 */
-	private Map m_componentParameterMap = new HashMap();
-	private FormModel m_stateModel;
-	/**
-	 * Container that renders this
-	 * Page.
-	 */
-	protected Container m_panel;
-	private List m_actionListeners;
-	private List m_requestListeners;
-	/**
-	 * The title of the page to be added in the head of HTML output. The
-	 * title is wrapped in a Label to allow developers to add PrintListeners
-	 * to dynamically change the value of the title.
-	 */
-	private Label m_title;
-	/**
-	 * Stores the actual title for the current request. The title may be
-	 * generated with a PrintListener of the m_title Label.
-	 */
-	private RequestLocal m_currentTitle;
-	/**
-	 * A list of all the client-side stylesheets. The elements of the list
-	 * are of type Page.Stylesheet, defined at the end of this file.
-	 */
-	private List m_clientStylesheets;
-	private StringParameter m_selected;
-	private StringParameter m_controlEvent;
-	private StringParameter m_controlValue;
-	/**
-	 * The default (initial) visibility of components. The encoding is
-	 * identical to that for PageState.m_invisible.
-	 *
-	 * This variable is package-friendly since it needs to be accessed by
-	 * PageState.
-	 */
-	protected BitSet m_invisible;
-	/**
-	 * The PageErrorDisplay component that will display page state
-	 * validation errors on this page
-	 */
-	private Component m_errorDisplay;
-	/**
-	 * Indicates whether finish() has been called on this Page.
-	 */
-	private boolean m_finished = false;
-	/**
-	 * indicates whether pageState.stateAsURL() should export the entire
-	 * state for this page, or whether it should only export the control
-	 * event as a URL and use the HttpSession for the rest of the page
-	 * state.
-	 */
-	private boolean m_useHttpSession = false;
+    static {
+        s_log.debug("Static initalizer is starting...");
+        CONTROL_EVENT_KEYS = new ArrayList(3);
+        CONTROL_EVENT_KEYS.add(SELECTED);
+        CONTROL_EVENT_KEYS.add(CONTROL_EVENT);
+        CONTROL_EVENT_KEYS.add(CONTROL_VALUE);
+        s_log.debug("Static initalizer finished.");
+    }
 
-	/**
-	 * Returns
-	 * true if this page should export state through the
-	 * HttpSession instead of the URL query string. 

If this returns - * true, then PageState.stateAsURL() will only export the - * control event as a URL query string. If this returns - * false, then stateAsURL() will export the entire page - * state. - * - * - * @see PageState#stateAsURL - * - * @return true if this page should export state through - * the HttpSession; false if it should export using the URL - * query string. - */ - public boolean isUsingHttpSession() { - return m_useHttpSession; - } + /** + * The name of the request parameter used for the visibility state of components stored in + * m_invisible. + */ + static final String INVISIBLE = INTERNAL + "i"; + /** + * Map of stateful components (id --> Component) SortedMap used because component based hash for + * page is based on concatenation of component ids, and so need to guarantee that they are + * returned in the same order for the same page - cg. + */ + private SortedMap m_componentMap; + private List m_components; + /** + * Map of component -> owned parameter collection + */ + private Map m_componentParameterMap = new HashMap(); + private FormModel m_stateModel; + /** + * Container that renders this Page. + */ + protected Container m_panel; + private List m_actionListeners; + private List m_requestListeners; + /** + * The title of the page to be added in the head of HTML output. The title is wrapped in a Label + * to allow developers to add PrintListeners to dynamically change the value of the title. + */ + private Label m_title; + /** + * Stores the actual title for the current request. The title may be generated with a + * PrintListener of the m_title Label. + */ + private RequestLocal m_currentTitle; + /** + * A list of all the client-side stylesheets. The elements of the list are of type + * Page.Stylesheet, defined at the end of this file. + */ + private List m_clientStylesheets; + private StringParameter m_selected; + private StringParameter m_controlEvent; + private StringParameter m_controlValue; + /** + * The default (initial) visibility of components. The encoding is identical to that for + * PageState.m_invisible. + * + * This variable is package-friendly since it needs to be accessed by PageState. + */ + protected BitSet m_invisible; + /** + * The PageErrorDisplay component that will display page state validation errors on this page + */ + private Component m_errorDisplay; + /** + * Indicates whether finish() has been called on this Page. + */ + private boolean m_finished = false; + /** + * indicates whether pageState.stateAsURL() should export the entire state for this page, or + * whether it should only export the control event as a URL and use the HttpSession for the rest + * of the page state. + */ + private boolean m_useHttpSession = false; - /** - * Indicates to this page whether it should export its entire state to - * subsequent requests through the URL query string, or if it should use - * the HttpSession instead and only use the URL query string for the - * control event. - * - * @see PageState#stateAsURL - * - * @param b true if PageState.stateAsURL() will export only - * the control event as a URL query string. false if - * stateAsURL() will export the entire page state. - */ - public void setUsingHttpSession(boolean b) { - m_useHttpSession = b; - } + /** + * Returns true if this page should export state through the HttpSession instead of + * the URL query string. + *

+ * If this returns true, then PageState.stateAsURL() will only export the control + * event as a URL query string. If this returns false, then stateAsURL() will + * export the entire page state. + * + * + * @see PageState#stateAsURL + * + * @return true if this page should export state through the HttpSession; + * false if it should export using the URL query string. + */ + public boolean isUsingHttpSession() { + return m_useHttpSession; + } - /** - * Creates an empty page with the specified title and panel. - * - * @param title title for this page - * - * @param panel container for this page - */ - public Page(String title, Container panel) { - this(new Label(title), panel); - } + /** + * Indicates to this page whether it should export its entire state to subsequent requests + * through the URL query string, or if it should use the HttpSession instead and only use the + * URL query string for the control event. + * + * @see PageState#stateAsURL + * + * @param b true if PageState.stateAsURL() will export only the control event as a + * URL query string. false if stateAsURL() will export the entire page + * state. + */ + public void setUsingHttpSession(boolean b) { + m_useHttpSession = b; + } - /** - * Creates an empty page with the specified title and panel. - * - * @param title title for this page - * - * @param panel container for this page - */ - public Page(Label title, Container panel) { - super(); - m_actionListeners = new LinkedList(); - m_requestListeners = new LinkedList(); - m_panel = panel; - m_clientStylesheets = new ArrayList(); - m_components = new ArrayList(); - m_componentMap = new TreeMap(); - setErrorDisplay(new PageErrorDisplay()); - setTitle(title); + /** + * Creates an empty page with the specified title and panel. + * + * @param title title for this page + * + * @param panel container for this page + */ + public Page(String title, Container panel) { + this(new Label(title), panel); + } + + /** + * Creates an empty page with the specified title and panel. + * + * @param title title for this page + * + * @param panel container for this page + */ + public Page(Label title, Container panel) { + super(); + m_actionListeners = new LinkedList(); + m_requestListeners = new LinkedList(); + m_panel = panel; + m_clientStylesheets = new ArrayList(); + m_components = new ArrayList(); + m_componentMap = new TreeMap(); + setErrorDisplay(new PageErrorDisplay()); + setTitle(title); // Initialize the RequestLocal where the title for the current - // request will be kept - m_currentTitle = new RequestLocal() { - @Override - protected Object initialValue(PageState state) { - return m_title.firePrintEvent(state); - } - }; + // request will be kept + m_currentTitle = new RequestLocal() { + @Override + protected Object initialValue(PageState state) { + return m_title.firePrintEvent(state); + } + + }; // Initialize the set of state parameters to hold - // the ones necessary for keeping track of the selected component and - // the name and value of a 'control event' - m_selected = new StringParameter(SELECTED); - m_controlEvent = new StringParameter(CONTROL_EVENT); - m_controlValue = new StringParameter(CONTROL_VALUE); + // the ones necessary for keeping track of the selected component and + // the name and value of a 'control event' + m_selected = new StringParameter(SELECTED); + m_controlEvent = new StringParameter(CONTROL_EVENT); + m_controlValue = new StringParameter(CONTROL_VALUE); - m_stateModel = new FormModel("stateModel", true); - m_stateModel.addFormParam(m_selected); - m_stateModel.addFormParam(m_controlEvent); - m_stateModel.addFormParam(m_controlValue); + m_stateModel = new FormModel("stateModel", true); + m_stateModel.addFormParam(m_selected); + m_stateModel.addFormParam(m_controlEvent); + m_stateModel.addFormParam(m_controlValue); - // Set up the visibility tracking parameters - m_invisible = new BitSet(32); - BitSetParameter p = new BitSetParameter(INVISIBLE, - BitSetParameter.ENCODE_DGAP); - m_stateModel.addFormParam(p); - } + // Set up the visibility tracking parameters + m_invisible = new BitSet(32); + BitSetParameter p = new BitSetParameter(INVISIBLE, + BitSetParameter.ENCODE_DGAP); + m_stateModel.addFormParam(p); + } - /** - * Creates an empty page with default title and implicit BoxPanel - * container. - */ - public Page() { - this(""); - } + /** + * Creates an empty page with default title and implicit BoxPanel container. + */ + public Page() { + this(""); + } - /** - * Creates an empty page with the specified title and implicit BoxPanel - * container. - * - * @param title title for this page - */ - public Page(Label title) { - this(title, new BoxPanel()); - BoxPanel bp = (BoxPanel) m_panel; - bp.setWidth("100%"); - } + /** + * Creates an empty page with the specified title and implicit BoxPanel container. + * + * @param title title for this page + */ + public Page(Label title) { + this(title, new BoxPanel()); + BoxPanel bp = (BoxPanel) m_panel; + bp.setWidth("100%"); + } - /** - * Creates an empty page with the specified title and implicit BoxPanel - * container. - * - * @param title title for this page - */ - public Page(String title) { - this(new Label(title)); - } + /** + * Creates an empty page with the specified title and implicit BoxPanel container. + * + * @param title title for this page + */ + public Page(String title) { + this(new Label(title)); + } - /** - * Adds a component to this container. - * - * @param c component to add to this container - */ - @Override - public void add(Component c) { - m_panel.add(c); + /** + * Adds a component to this container. + * + * @param c component to add to this container + */ + @Override + public void add(Component c) { + m_panel.add(c); - } + } - /** - * Adds a component with the specified layout constraints to this - * container. Layout constraints are defined in each layout container as - * static ints. To specify multiple constraints, use bitwise OR. - * - * @param c component to add to this container - * - * @param constraints layout constraints (a bitwise OR of static ints in - * the particular layout) - */ - @Override - public void add(Component c, int constraints) { - m_panel.add(c, constraints); - } + /** + * Adds a component with the specified layout constraints to this container. Layout constraints + * are defined in each layout container as static ints. To specify multiple constraints, use + * bitwise OR. + * + * @param c component to add to this container + * + * @param constraints layout constraints (a bitwise OR of static ints in the particular layout) + */ + @Override + public void add(Component c, int constraints) { + m_panel.add(c, constraints); + } - /** - * Returns - * true if this list contains the specified element. More - * formally, returns - * true if and only if this list contains at least one - * element e such that (o==null ? e==null : o.equals(e)).

This - * method returns - * true only if the component has been directly added to - * this container. If this container contains another container that - * contains this component, this method returns - * false. - * - * @param o element whose presence in this container is to be tested - * - * @return true if this Container contains the specified - * component directly; false otherwise. - */ - @Override - public boolean contains(Object o) { - return m_panel.contains(o); - } + /** + * Returns true if this list contains the specified element. More formally, returns + * true if and only if this list contains at least one element e such that (o==null + * ? e==null : o.equals(e)). + *

+ * This method returns true only if the component has been directly added to this + * container. If this container contains another container that contains this component, this + * method returns false. + * + * @param o element whose presence in this container is to be tested + * + * @return true if this Container contains the specified component directly; + * false otherwise. + */ + @Override + public boolean contains(Object o) { + return m_panel.contains(o); + } - /** - * Returns the component at the specified position. Each call to the add - * method increments the index. Since the user has no control over the - * index of added components (other than counting each call to add), - * this method should be used in conjunction with indexOf. - * - * @param index the index of the item to be retrieved from this - * Container - * - * @return the component at the specified position in this container. - */ - @Override - public Component get(int index) { - return m_panel.get(index); - } + /** + * Returns the component at the specified position. Each call to the add method increments the + * index. Since the user has no control over the index of added components (other than counting + * each call to add), this method should be used in conjunction with indexOf. + * + * @param index the index of the item to be retrieved from this Container + * + * @return the component at the specified position in this container. + */ + @Override + public Component get(int index) { + return m_panel.get(index); + } - /** - * Gets the index of a component. - * - * @param c component to search for - * - * @return the index in this list of the first occurrence of the - * specified element, or -1 if this list does not contain this element. - * - * @pre c != null - * @post contains(c) implies (return >= 0) && (return < size()) - * @post !contains(c) implies return == -1 - */ - @Override - public int indexOf(Component c) { - return m_panel.indexOf(c); - } + /** + * Gets the index of a component. + * + * @param c component to search for + * + * @return the index in this list of the first occurrence of the specified element, or -1 if + * this list does not contain this element. + * + * @pre c != null + * @post contains(c) implies (return >= 0) && (return < size()) + * @pos + * t !contains(c) implies return == -1 + */ + @Override + public int indexOf(Component c) { + return m_panel.indexOf(c); + } - /** - * Returns - * true if the container contains no components. - * - * @return true if this container contains no * * - * components; false otherwise. - */ - @Override - public boolean isEmpty() { - return m_panel.isEmpty(); - } + /** + * Returns true if the container contains no components. + * + * @return true if this container contains no * * components; false + * otherwise. + */ + @Override + public boolean isEmpty() { + return m_panel.isEmpty(); + } - /** - * Returns the number of elements in this container. This does not - * recursively count the components that are indirectly contained in - * this container. - * - * @return the number of components directly in this container. - */ - @Override - public int size() { - return m_panel.size(); - } + /** + * Returns the number of elements in this container. This does not recursively count the + * components that are indirectly contained in this container. + * + * @return the number of components directly in this container. + */ + @Override + public int size() { + return m_panel.size(); + } - @Override - public Iterator children() { - return Collections.singletonList(m_panel).iterator(); - } + @Override + public Iterator children() { + return Collections.singletonList(m_panel).iterator(); + } - /** - * Returns the panel that the - * Page uses for rendering its components. - * - * @return the panel. - */ - public final Container getPanel() { - return m_panel; - } + /** + * Returns the panel that the Page uses for rendering its components. + * + * @return the panel. + */ + public final Container getPanel() { + return m_panel; + } - /** - * Set the Container used for rendering components on this page. Caution - * should be used with this function, as the existing container is - * simply overwritten. - * - * @author Matthew Booth (mbooth@redhat.com) - */ - public void setPanel(Container c) { - m_panel = c; - } + /** + * Set the Container used for rendering components on this page. Caution should be used with + * this function, as the existing container is simply overwritten. + * + * @author Matthew Booth (mbooth@redhat.com) + */ + public void setPanel(Container c) { + m_panel = c; + } - /** - *

Retrieves the title of this page.

- * - * @return the static title of this page. - */ - public final Label getTitle() { - return m_title; - } + /** + *

+ * Retrieves the title of this page.

+ * + * @return the static title of this page. + */ + public final Label getTitle() { + return m_title; + } - /** - * Retrieves the title of this page as a Bebop label component. - * - * @param state the state of the current request - * @return the title of the page for the current request. - */ - public final Label getTitle(PageState state) { - return (Label) m_currentTitle.get(state); - } + /** + * Retrieves the title of this page as a Bebop label component. + * + * @param state the state of the current request + * + * @return the title of the page for the current request. + */ + public final Label getTitle(PageState state) { + return (Label) m_currentTitle.get(state); + } - /** - * Sets the title for this page from the passed in string. - * - * @param title title for this page - */ - public void setTitle(String title) { - Assert.isUnlocked(this); - setTitle(new Label(title)); - } + /** + * Sets the title for this page from the passed in string. + * + * @param title title for this page + */ + public void setTitle(String title) { + Assert.isUnlocked(this); + setTitle(new Label(title)); + } - /** - * Set the title for this page from the passed in label. - * - * @param title title for this page - */ - public void setTitle(Label title) { - Assert.isUnlocked(this); - m_title = title; - } + /** + * Set the title for this page from the passed in label. + * + * @param title title for this page + */ + public void setTitle(Label title) { + Assert.isUnlocked(this); + m_title = title; + } - /** - * Sets the {@link Component} that will display the validation errors in - * the current {@link PageState}. Any validation error in the - * PageState will cause the - * Page to completely ignore all other components and - * render only the error display component.

By default, a - * {@link PageErrorDisplay} component is used to display the validation - * errors. - * - * @param c the component that will display the validation errors in the - * current PageState - */ - public final void setErrorDisplay(Component c) { - Assert.isUnlocked(this); - m_errorDisplay = c; - } + /** + * Sets the {@link Component} that will display the validation errors in the current + * {@link PageState}. Any validation error in the PageState will cause the + * Page to completely ignore all other components and render only the error display + * component. + *

+ * By default, a {@link PageErrorDisplay} component is used to display the validation errors. + * + * @param c the component that will display the validation errors in the current + * PageState + */ + public final void setErrorDisplay(Component c) { + Assert.isUnlocked(this); + m_errorDisplay = c; + } - /** - * Gets the {@link Component} that will display the validation errors in - * the current {@link PageState}. Any validation error in the - * PageState will cause the - * Page to completely ignore all other components and - * render only the error display component.

By default, a - * {@link PageErrorDisplay} component is used to display the validation - * errors. - * - * @return the component that will display the validation errors in the - * current PageState. - */ - public final Component getErrorDisplay() { - return m_errorDisplay; - } + /** + * Gets the {@link Component} that will display the validation errors in the current + * {@link PageState}. Any validation error in the PageState will cause the + * Page to completely ignore all other components and render only the error display + * component. + *

+ * By default, a {@link PageErrorDisplay} component is used to display the validation errors. + * + * @return the component that will display the validation errors in the current + * PageState. + */ + public final Component getErrorDisplay() { + return m_errorDisplay; + } - /** - * Adds a client-side stylesheet that should be used in HTML output. - * Arbitrarily many client-side stylesheets can be added with this - * method. To use a CSS stylesheet, call something like - * setStyleSheet("style.css", "text/css"). - * - *

These values will ultimately wind up in a <link> - * tag in the head of the HTML page. - * - *

Note that the stylesheet set with this call has nothing to do - * with the XSLT stylesheet (transformer) that is applied to the XML - * generated from this page! - * - * @param styleSheetURI the location of the stylesheet - * @param mimeType the MIME type of the stylesheet, usually - * text/css - * @pre ! isLocked() - */ - public void addClientStylesheet(String styleSheetURI, String mimeType) { - m_clientStylesheets.add(new Stylesheet(styleSheetURI, mimeType)); - } + /** + * Adds a client-side stylesheet that should be used in HTML output. Arbitrarily many + * client-side stylesheets can be added with this method. To use a CSS stylesheet, call + * something like setStyleSheet("style.css", "text/css"). + * + *

+ * These values will ultimately wind up in a <link> + * tag in the head of the HTML page. + * + *

+ * Note that the stylesheet set with this call has nothing to do with the XSLT stylesheet + * (transformer) that is applied to the XML generated from this page! + * + * @param styleSheetURI the location of the stylesheet + * @param mimeType the MIME type of the stylesheet, usually + * text/css + * + * @pre ! isLocked() + */ + public void addClientStylesheet(String styleSheetURI, String mimeType) { + m_clientStylesheets.add(new Stylesheet(styleSheetURI, mimeType)); + } - /** - * Adds a global state parameter to this page. Global parameters are - * values that need to be preserved between requests, but that have no - * special connection to any of the components on the page. For a page - * that displays details about an item, a global parameter would be used - * to identify the item. - * - *

If the parameter was previously added as a component state - * parameter, its name is unmangled and stays unmangled. - * - * @param p the global parameter to add - * - * @see #addComponentStateParam - * - * @pre ! isLocked() - * @pre parameter != null - */ - public void addGlobalStateParam(ParameterModel p) { - Assert.isUnlocked(this); - p.setName(unmangle(p.getName())); - m_stateModel.addFormParam(p); - } + /** + * Adds a global state parameter to this page. Global parameters are values that need to be + * preserved between requests, but that have no special connection to any of the components on + * the page. For a page that displays details about an item, a global parameter would be used to + * identify the item. + * + *

+ * If the parameter was previously added as a component state parameter, its name is unmangled + * and stays unmangled. + * + * @param p the global parameter to add + * + * @see #addComponentStateParam + * + * @pre ! isLocked() + * @pre parameter != null + */ + public void addGlobalStateParam(ParameterModel p) { + Assert.isUnlocked(this); + p.setName(unmangle(p.getName())); + m_stateModel.addFormParam(p); + } - /** - * Constructs the top nodes of the DOM or JDOM tree. Used by - * generateXML(PageState, Document) below.

Generates DOM fragment: - *

-	 * <bebop:page>
-	 *   <bebop:title> ... value set with setTitle ... </bebop:title>
-	 *   <bebop:stylesheet href='styleSheetURI' type='mimeType'>
-	 *   ... page content gnerated by children ...
-	 * </bebop:page>
The content of the <title> - * element can be set by calling {@link #setTitle setTitle}. The - * <stylesheet> element will only be present if a - * stylesheet has been set with {@link - * #setStyleSheet setStyleSheet}. - * - * @param ps the page state for the current page - * @param parent the DOM node for the whole Document - * - * @pre isLocked() - */ - protected Element generateXMLHelper(PageState ps, Document parent) { - Assert.isLocked(this); + /** + * Constructs the top nodes of the DOM or JDOM tree. Used by generateXML(PageState, Document) + * below. + *

+ * Generates DOM fragment: + *

+     * <bebop:page>
+     *   <bebop:title> ... value set with setTitle ... </bebop:title>
+     *   <bebop:stylesheet href='styleSheetURI' type='mimeType'>
+     *   ... page content gnerated by children ...
+     * </bebop:page>
The content of the <title> + * element can be set by calling {@link #setTitle setTitle}. The + * <stylesheet> element will only be present if a stylesheet has been set with {@link + * #setStyleSheet setStyleSheet}. + * + * @param ps the page state for the current page + * @param parent the DOM node for the whole Document + * + * @pre isLocked() + */ + protected Element generateXMLHelper(PageState ps, Document parent) { + Assert.isLocked(this); - Element page = parent.createRootElement("bebop:page", BEBOP_XML_NS); - exportAttributes(page); + Element page = parent.createRootElement("bebop:page", BEBOP_XML_NS); + exportAttributes(page); - /* Generator information */ - exportSystemInformation(page); + /* Generator information */ + exportSystemInformation(page); - Element title = page.newChildElement("bebop:title", BEBOP_XML_NS); - title.setText(getTitle(ps).getLabel(ps)); + Element title = page.newChildElement("bebop:title", BEBOP_XML_NS); + title.setText(getTitle(ps).getLabel(ps)); - for (Iterator i = m_clientStylesheets.iterator(); i.hasNext();) { - ((Stylesheet) i.next()).generateXML(page); - } + for (Iterator i = m_clientStylesheets.iterator(); i.hasNext();) { + ((Stylesheet) i.next()).generateXML(page); + } - return page; - } + return page; + } - /** - * Constructs a DOM or JDOM tree with all components on the page. The - * tree represents the page that results from the - * {@link javax.servlet.http.HttpServletRequest} kept in the - * state. - * - * @param state the page state produced by {@link #process} - * @param parent the DOM node for the whole Document - * @see #process process - * @pre isLocked() - * @pre state != null - */ - public void generateXML(PageState state, Document parent) { - // always export page state as HTTP session - if (m_useHttpSession) { - state.stateAsHttpSession(); - } + /** + * Constructs a DOM or JDOM tree with all components on the page. The tree represents the page + * that results from the {@link javax.servlet.http.HttpServletRequest} kept in the + * state. + * + * @param state the page state produced by {@link #process} + * @param parent the DOM node for the whole Document + * + * @see #process process + * @pre isLocked() + * @pre state != null + */ + public void generateXML(PageState state, Document parent) { + // always export page state as HTTP session + if (m_useHttpSession) { + state.stateAsHttpSession(); + } - Element page = generateXMLHelper(state, parent); + Element page = generateXMLHelper(state, parent); // If the page state has errors, ignore all the components and - // render only the error display component - if (state.getErrors().hasNext()) { - m_errorDisplay.generateXML(state, page); - } else { - m_panel.generateXML(state, page); - } + // render only the error display component + if (state.getErrors().hasNext()) { + m_errorDisplay.generateXML(state, page); + } else { + m_panel.generateXML(state, page); + } - if (Kernel.getConfig().isDebugEnabled() && debugStructure(state. - getRequest())) { + if (Kernel.getConfig().isDebugEnabled() && debugStructure(state. + getRequest())) { - Element structure = - page.newChildElement("bebop:structure", BEBOP_XML_NS); + Element structure = page.newChildElement("bebop:structure", BEBOP_XML_NS); - showStructure(state, structure); - } - } + showStructure(state, structure); + } + } - private static boolean debugStructure(HttpServletRequest req) { - return "transform".equals(req.getParameter("debug")); - } + private static boolean debugStructure(HttpServletRequest req) { + return "transform".equals(req.getParameter("debug")); + } - /** - * Do nothing. Top-level add nodes is meaningless. - */ - @Override - public void generateXML(PageState state, Element elt) { - } + /** + * Do nothing. Top-level add nodes is meaningless. + */ + @Override + public void generateXML(PageState state, Element elt) { + } - /** - * Creates a PageState object and processes it by calling the respond - * method on the selected component. Processes a request by notifying - * the component from which the process originated and {@link #fireActionEvent - * broadcasts} an {@link ActionEvent} to all the listeners that - * registered with {@link #addActionListener addActionListener}. - * - * @see #generateXML(PageState,Document) generateXML - * @pre isLocked() - * @pre request != null - * @pre response != null - */ - public PageState process(HttpServletRequest request, - HttpServletResponse response) - throws ServletException { + /** + * Creates a PageState object and processes it by calling the respond method on the selected + * component. Processes a request by notifying the component from which the process originated + * and {@link #fireActionEvent + * broadcasts} an {@link ActionEvent} to all the listeners that registered with + * {@link #addActionListener addActionListener}. + * + * @see #generateXML(PageState,Document) generateXML + * @pre isLocked() + * @pre request != null + * @pre response != null + */ + public PageState process(HttpServletRequest request, + HttpServletResponse response) + throws ServletException { - PageState result = new PageState(this, request, response); - try { - DeveloperSupport.startStage("Bebop Page Process"); - process(result); - } finally { - DeveloperSupport.endStage("Bebop Page Process"); - } - return result; - } + PageState result = new PageState(this, request, response); + try { + DeveloperSupport.startStage("Bebop Page Process"); + process(result); + } finally { + DeveloperSupport.endStage("Bebop Page Process"); + } + return result; + } - /** - * Processes the supplied PageState object according to this PageModel. - * Calls the respond method on the selected Bebop component. - */ - public void process(PageState state) throws ServletException { - Assert.isLocked(this); - try { - DeveloperSupport.startStage("Bebop Request Event"); - fireRequestEvent(state); - } finally { - DeveloperSupport.endStage("Bebop Request Event"); - } + /** + * Processes the supplied PageState object according to this PageModel. Calls the respond method + * on the selected Bebop component. + */ + public void process(PageState state) throws ServletException { + Assert.isLocked(this); + try { + DeveloperSupport.startStage("Bebop Request Event"); + fireRequestEvent(state); + } finally { + DeveloperSupport.endStage("Bebop Request Event"); + } // Validate the state; any errors in the state will be displayed - // by generateXML - state.forceValidate(); + // by generateXML + state.forceValidate(); - if (state.isValid()) { - try { - DeveloperSupport.startStage("Bebop Respond"); - state.respond(); - } finally { - DeveloperSupport.endStage("Bebop Respond"); - } - try { - DeveloperSupport.startStage("Bebop Action Event"); - fireActionEvent(state); - } finally { - DeveloperSupport.endStage("Bebop Action Event"); - } - } - } + if (state.isValid()) { + try { + DeveloperSupport.startStage("Bebop Respond"); + state.respond(); + } finally { + DeveloperSupport.endStage("Bebop Respond"); + } + try { + DeveloperSupport.startStage("Bebop Action Event"); + fireActionEvent(state); + } finally { + DeveloperSupport.endStage("Bebop Action Event"); + } + } + } // /** // * Does all the servicing of a request except output generation. @@ -707,627 +688,625 @@ public class Page extends BlockStylable implements Container { // PageState state = process(req, res); // return state; // } - /** - * Builds a DOM Document from the current request state by doing a - * depth-first tree walk on the current set of components in this Page, - * calling generateXML on each. Does NOT do the rendering. If the HTTP - * response has already been committed, does not build the XML document. - * - * @return a DOM ready for rendering, or null if the response has - * already been committed. - * @post res.isCommitted() == (return == null) - */ - public Document buildDocument(HttpServletRequest req, - HttpServletResponse res) - throws ServletException { - try { - Document doc = new Document(); - PageState state = process(req, res); + /** + * Builds a DOM Document from the current request state by doing a depth-first tree walk on the + * current set of components in this Page, calling generateXML on each. Does NOT do the + * rendering. If the HTTP response has already been committed, does not build the XML document. + * + * @return a DOM ready for rendering, or null if the response has already been committed. + * + * @post res.isCommitted() == (return == null) + */ + public Document buildDocument(HttpServletRequest req, + HttpServletResponse res) + throws ServletException { + try { + Document doc = new Document(); + PageState state = process(req, res); // only generate XML document if the response is not already - // committed - if (!res.isCommitted()) { - try { - DeveloperSupport.startStage("Bebop XML"); - Profiler.startOp("XML"); - generateXML(state, doc); - } finally { - DeveloperSupport.endStage("Bebop XML"); - Profiler.stopOp("XML"); - } - return doc; - } else { - return null; - } - } catch (ParserConfigurationException e) { - throw new ServletException(e); - } - } - - /** - * Finishes building the page. The tree of components is traversed and - * each component is told to add its state parameters to the page's - * state model. - * - * @pre ! isLocked() - */ - private void finish() { - if (!m_finished) { - Assert.isUnlocked(this); - - Traversal componentRegistrar = new Traversal() { - @Override - protected void act(Component c) { - addComponent(c); - c.register(Page.this); - } - }; - if (m_panel == null) { - s_log.warn("m_panel is null"); - } - componentRegistrar.preorder(m_panel); - if (m_errorDisplay != null) { - addComponent(m_errorDisplay); - m_errorDisplay.register(Page.this); - } - - m_finished = true; - } - } - - /** - * Locks the page and all its components against further modifications. - * - *

Locking a page helps in finding mistakes that result from - * modifying a page's structure.

- */ - @Override - public void lock() { - if (!m_finished) { - finish(); - } - m_stateModel.lock(); - Traversal componentLocker = new Traversal() { - @Override - protected void act(Component c) { - c.lock(); - } - }; - - componentLocker.preorder(m_panel); - - super.lock(); - } - - @Override - public void respond(PageState state) throws javax.servlet.ServletException { - throw new UnsupportedOperationException(); - } - - /** - * Registers a listener that is notified whenever a request to this page - * is made, after the selected component has had a chance to respond. - * - * @pre l != null - * @pre ! isLocked() - */ - public void addActionListener(ActionListener l) { - Assert.isUnlocked(this); - m_actionListeners.add(l); - } - - /** - * Remove a previously registered action listener. - * - * @pre l != null - * @pre ! isLocked() - */ - public void removeActionListener(ActionListener l) { - Assert.isUnlocked(this); - m_actionListeners.remove(l); - } - - /** - * Registers a listener that is notified whenever a request to this page - * is made, before the selected component has had a chance to respond. - * - * @pre l != null - * @pre ! isLocked() - */ - public void addRequestListener(RequestListener l) { - Assert.isUnlocked(this); - m_requestListeners.add(l); - } - - /** - * Removes a previously registered request listener. - * - * @param 1 the listener to remove - * @pre l != null - * @pre ! isLocked() - */ - public void removeRequestListener(RequestListener l) { - Assert.isUnlocked(this); - m_requestListeners.remove(l); - } - - /** - * Broadcasts an {@link ActionEvent} to all registered listeners. The - * source of the event is this page, and the state recorded in the event - * is the one resulting from processing the current request. - * - * @param the state for this event - * - * @pre state != null - */ - protected void fireActionEvent(PageState state) { - ActionEvent e = null; - - for (Iterator i = m_actionListeners.iterator(); i.hasNext();) { - if (e == null) { - e = new ActionEvent(this, state); - } - - final ActionListener listener = (ActionListener) i.next(); - - if (s_log.isDebugEnabled()) { - s_log.debug("Firing action listener " + listener); - } - - listener.actionPerformed(e); - } - } - - /** - * Broadcasts a {@link RequestEvent} to all registered listeners. The - * source of the event is this page, and the state recorded in the event - * is the one resulting from processing the current request. - * - * @param state the state for this event - * - * @pre state != null - */ - protected void fireRequestEvent(PageState state) { - RequestEvent e = null; - - for (Iterator i = m_requestListeners.iterator(); i.hasNext();) { - if (e == null) { - e = new RequestEvent(this, state); - } - - final RequestListener listener = (RequestListener) i.next(); - - if (s_log.isDebugEnabled()) { - s_log.debug("Firing request listener " + listener); - } - - listener.pageRequested(e); - } - } - - /** - * Export page generator information if set. The m_pageGenerator is a - * HashMap containing the information as key value. In general this - * should include generator name and generator version. - * - * @param page parent element - should be bebeop:page - * - * @pre m_pageGenerator != null && !m_pageGenerator.isEmpty() - */ - final protected void exportSystemInformation(Element page) { - SystemInformation sysInfo = SystemInformation.getInstance(); - if (!sysInfo.isEmpty()) { - Element gen = page.newChildElement("bebop:systemInformation", BEBOP_XML_NS); - - Iterator> keyValues = sysInfo.iterator(); - while (keyValues.hasNext()) { - Map.Entry entry = keyValues.next(); - gen.addAttribute(entry.getKey(), entry.getValue()); - } - } - } - - // Client-side stylesheet storage - private class Stylesheet { - - String m_URI; - String m_type; - - public Stylesheet(String stylesheetURI, String mimeType) { - m_URI = stylesheetURI; - m_type = mimeType; - } - - public void generateXML(Element parent) { - Element style = parent.newChildElement("bebop:stylesheet", - BEBOP_XML_NS); - style.addAttribute("href", m_URI); - if (m_type != null) { - style.addAttribute("type", m_type); - } - } - } - - /** - * Adds a component to the page model. - * - * @deprecated This method will become private in ACS 5.0. - */ - public void addComponent(Component c) { - Assert.isUnlocked(this); - - if (!stateContains(c)) { - if (c == null) { - s_log.error("c is null"); - } /*else { - s_log.error("c: " + c.toString()); - }*/ - String key = c.getKey(); - if (key == null) { - key = Integer.toString(m_components.size()); - } - if (m_componentMap.get(key) != null) { - throw new IllegalArgumentException( - "Component key must not be duplicated. The key " + key - + " is shared by more than one component."); - } - m_componentMap.put(key, c); - m_components.add(c); - } - } - - /** - * Registers a state parameter for a component. It is permissible to - * register the same state parameter several times, from the same or - * different components. The name of the parameter will be changed to - * ensure that it won't clash with any other component's parameter. If - * the parameter is added more than once, the name is only changed the - * first time it is added. - * - * @param c the component to register the parameter for - * @param p the state parameter to register - * - * @see #addGlobalStateParam - * - * @pre stateContains(c) - * @pre ! isLocked() - * @pre p != null - */ - public void addComponentStateParam(Component c, ParameterModel p) { - Assert.isUnlocked(this); - - if (!stateContains(c)) { - throw new IllegalArgumentException( - "Component must be registered in Page"); - } - if (!m_stateModel.containsFormParam(p)) { - String name = parameterName(c, p.getName()); - s_log.debug(String.format("Setting name of parameter to add to '%s'", - name)); - p.setName(name); - m_stateModel.addFormParam(p); - - Collection params = (Collection) m_componentParameterMap.get(c); - if (params == null) { - params = new ArrayList(); - m_componentParameterMap.put(c, params); - } - params.add(p); - } - } - - /** - *

Get the parameters registered for a given component.

- */ - public Collection getComponentParameters(Component c) { - return (Collection) m_componentParameterMap.get(c); - } - - /** - * Gets the state index of a component. This is the number assigned to - * the component in the register traveral - * - * @param c the component to search for - * - * @return the index in this list of the first occurrence of the - * specified element, or -1 if this list does not contain this element. - * - * @pre c != null - * @post contains(c) implies (return >= 0) && (return < size()) - * @post !contains(c) implies return == -1 - */ - public int stateIndex(Component c) { - return m_components.indexOf(c); - } - - /** - * The number of components in the page model. - * - * @post return >= 0 - */ - public int stateSize() { - return m_components.size(); - } - - /** - * Checks whether this component is already in the page model. - * - * @pre c != null - */ - public boolean stateContains(Component c) { - return m_components.contains(c); - } - - /** - * Gets a page component by index. - * - * @pre (i >= 0) && (i < size()) - * @post return != null - */ - public Component getComponent(int i) { - return (Component) m_components.get(i); - } - - /** - * Gets a page component by key. - * - * @pre s != null - */ - Component getComponent(String s) { - return (Component) m_componentMap.get(s); - } - - /** - * Gets the form model that contains the parameters for the page's - * state. - */ - public final FormModel getStateModel() { - return m_stateModel; - } - - /** - * Gets the ParameterModels held in this Page. - * - * @return an iterator of ParameterModels. - */ - public Iterator getParameters() { - return m_stateModel.getParameters(); - } - - /** - * Checks whether the specified component is visible by default on the - * page. - * - * @param c a component contained in the page - * @return true if the component is visible by default; - * false otherwise. - * @see #setVisibleDefault setVisibleDefault - * @see Component#setVisible Component.setVisible - */ - public boolean isVisibleDefault(Component c) { - Assert.isTrue(stateContains(c)); - - return !m_invisible.get(stateIndex(c)); - } - - /** - * Sets whether the specified component is visible by default. The - * default visibility is used when a page is displayed for the first - * time and on subsequent requests until the visibility of a component - * is changed explicitly with {@link Component#setVisible - * Component.setVisible}. - * - *

When a component is first added to a page, it is visible. - * - * @param c a component whose visibility is to be set - * @param v true if the component is visible; - * false otherwise. - * @see Component#setVisible Component.setVisible - * @see Component#register Component.register - */ - public void setVisibleDefault(Component c, boolean v) { - Assert.isUnlocked(this); - - addComponent(c); - int i = stateIndex(c); - if (v) { - m_invisible.clear(i); - } else { - m_invisible.set(i); - } - } - - /** - * The global name of the parameter - * name in the component - * c. - */ - public String parameterName(Component c, String name) { - if (c == null || !stateContains(c)) { - return name; - } - - return componentPrefix(c) + name; - } - - /** - * The global name of the parameter - * name. - */ - public String parameterName(String name) { - return parameterName(null, name); - } - - void reset(final PageState ps, Component cmpnt) { - Traversal resetter = new Traversal() { - @Override - protected void act(Component c) { - Collection cp = getComponentParameters(c); - if (cp != null) { - Iterator iter = cp.iterator(); - while (iter.hasNext()) { - ParameterModel p = (ParameterModel) iter.next(); - ps.setValue(p, null); - } - } - c.setVisible(ps, isVisibleDefault(c)); - } - }; - resetter.preorder(cmpnt); - } - - /** - * Return the prefix that is prepended to each component's state - * parameters to keep them unique. - */ - private final String componentPrefix(Component c) { - if (c == null) { - return COMPONENT_PREFIX + "g" + DELIMITER; - } else { - // WRS: preferentially use key if it exists - String key = c.getKey(); - if (key == null) { - if (stateContains(c)) { - key = String.valueOf(stateIndex(c)); - } else { - throw new IllegalArgumentException( - "Cannot generate prefix for component: key is null " - + "and component " + c.toString() + "/" + c.getKey() - + " did not register with page."); - } - } - return COMPONENT_PREFIX + key + DELIMITER; - } - } - - /** - * Undo the name change that {@link #parameterName} does. - * - * @param name a possibly mangled name - * @return the unmangled name. - */ - private static final String unmangle(String name) { - if (!name.startsWith(COMPONENT_PREFIX)) { - return name; - } - // Find the second occurence of delimiter - int prefix = name.indexOf(DELIMITER, name.indexOf(DELIMITER) + 1); - if (prefix >= 0 && prefix < name.length()) { - return name.substring(prefix + 1); - } - return name; - } - // Procs for debugging output - private static String NAME = "name"; - - /** - * Produces an XML fragment that captures the layout of this page. - */ - private void showStructure(PageState s, Element root) { - final HttpServletRequest req = s.getRequest(); - Element state = root.newChildElement("bebop:state", BEBOP_XML_NS); - // Selected component - String sel = req.getParameter(m_selected.getName()); - Element selected = state.newChildElement("bebop:selected", BEBOP_XML_NS); - - selected.addAttribute(NAME, m_selected.getName()); - selected.setText(sel); - - // Control event - Element eventName = - state.newChildElement("bebop:eventName", BEBOP_XML_NS); - eventName.addAttribute(NAME, m_controlEvent.getName()); - eventName.setText(req.getParameter(m_controlEvent.getName())); - Element eventValue = - state.newChildElement("bebop:eventValue", BEBOP_XML_NS); - eventValue.addAttribute(NAME, m_controlValue.getName()); - eventValue.setText(req.getParameter(m_controlValue.getName())); - - // Global parameters - Element globalState = - root.newChildElement("bebop:params", BEBOP_XML_NS); - for (Iterator ii = getStateModel().getParameters(); ii.hasNext();) { - ParameterModel p = (ParameterModel) ii.next(); - if (!p.getName().startsWith(COMPONENT_PREFIX)) { - Element param = - globalState.newChildElement("bebop:param", BEBOP_XML_NS); - param.addAttribute(NAME, p.getName()); - param.setText(String.valueOf(s.getValue(p))); - } - } - - showVisibility(s, this, root); - } - - /** - * @see showStructure(PageState, Element) - */ - private void showVisibility(PageState s, Component c, Element parent) { - HttpServletRequest req = s.getRequest(); - - Element cmp = parent.newChildElement("bebop:component", BEBOP_XML_NS); - cmp.addAttribute(NAME, getDebugLabel(c)); - cmp.addAttribute("idx", String.valueOf(stateIndex(c))); - cmp.addAttribute("isVisible", (s.isVisible(c) ? "yes" : "no")); - cmp.addAttribute("class", c.getClass().getName()); - - if (c.getKey() != null) { - String prefix = componentPrefix(c); - for (Iterator i = getStateModel().getParameters(); i.hasNext();) { - ParameterModel p = (ParameterModel) i.next(); - if (!p.getName().startsWith(prefix)) { - continue; - } - - Element param = - parent.newChildElement("bebop:param", BEBOP_XML_NS); - param.addAttribute(NAME, unmangle(p.getName())); - param.addAttribute("defaultValue", - String.valueOf(req.getParameter(p.getName()))); - param.addAttribute("currentValue", String.valueOf(s.getValue(p))); - } - } - for (Iterator i = c.children(); i.hasNext();) { - showVisibility(s, ((Component) i.next()), cmp); - } - } - - private static String getDebugLabel(Component c) { - if (c.getKey() != null) { - return c.getKey(); - } - - String klass = c.getClass().getName(); - return klass.substring(klass.lastIndexOf(".") + 1, klass.length()); - } - - /** - * return a string that represents an ordered list of component ids used - * on the page. For situations where only the components present is of - * importance, this may be used by implementations of hashCode & equals - * - * @return - */ - public String getComponentString() { - Iterator it = m_componentMap.keySet().iterator(); - /*int hash = 0; - while (it.hasNext()) { - String componentId = (String)it.next(); - s_log.debug("component id = " + componentId); - hash = hash | componentId.hashCode(); - s_log.debug("hash so far = " + hash); - }*/ - Date start = new Date(); - - StringBuilder hashString = new StringBuilder(); - while (it.hasNext()) { - String componentId = (String) it.next(); - hashString.append(componentId); - } - s_log.debug("Time to create hashCode for page: " + (new Date().getTime() - start. - getTime())); - return hashString.toString(); - - - } + // committed + if (!res.isCommitted()) { + try { + DeveloperSupport.startStage("Bebop XML"); + Profiler.startOp("XML"); + generateXML(state, doc); + } finally { + DeveloperSupport.endStage("Bebop XML"); + Profiler.stopOp("XML"); + } + return doc; + } else { + return null; + } + } catch (ParserConfigurationException e) { + throw new ServletException(e); + } + } + + /** + * Finishes building the page. The tree of components is traversed and each component is told to + * add its state parameters to the page's state model. + * + * @pre ! isLocked() + */ + private void finish() { + if (!m_finished) { + Assert.isUnlocked(this); + + Traversal componentRegistrar = new Traversal() { + @Override + protected void act(Component c) { + addComponent(c); + c.register(Page.this); + } + + }; + if (m_panel == null) { + s_log.warn("m_panel is null"); + } + componentRegistrar.preorder(m_panel); + if (m_errorDisplay != null) { + addComponent(m_errorDisplay); + m_errorDisplay.register(Page.this); + } + + m_finished = true; + } + } + + /** + * Locks the page and all its components against further modifications. + * + *

+ * Locking a page helps in finding mistakes that result from modifying a page's structure.

+ */ + @Override + public void lock() { + if (!m_finished) { + finish(); + } + m_stateModel.lock(); + Traversal componentLocker = new Traversal() { + @Override + protected void act(Component c) { + c.lock(); + } + + }; + + componentLocker.preorder(m_panel); + + super.lock(); + } + + @Override + public void respond(PageState state) throws javax.servlet.ServletException { + throw new UnsupportedOperationException(); + } + + /** + * Registers a listener that is notified whenever a request to this page is made, after the + * selected component has had a chance to respond. + * + * @pre l != null + * @pre ! isLocked() + */ + public void addActionListener(ActionListener l) { + Assert.isUnlocked(this); + m_actionListeners.add(l); + } + + /** + * Remove a previously registered action listener. + * + * @pre l != null + * @pre ! isLocked() + */ + public void removeActionListener(ActionListener l) { + Assert.isUnlocked(this); + m_actionListeners.remove(l); + } + + /** + * Registers a listener that is notified whenever a request to this page is made, before the + * selected component has had a chance to respond. + * + * @pre l != null + * @pre ! isLocked() + */ + public void addRequestListener(RequestListener l) { + Assert.isUnlocked(this); + m_requestListeners.add(l); + } + + /** + * Removes a previously registered request listener. + * + * @param 1 the listener to remove + * + * @pre l != null + * @pre ! isLocked() + */ + public void removeRequestListener(RequestListener l) { + Assert.isUnlocked(this); + m_requestListeners.remove(l); + } + + /** + * Broadcasts an {@link ActionEvent} to all registered listeners. The source of the event is + * this page, and the state recorded in the event is the one resulting from processing the + * current request. + * + * @param the state for this event + * + * @pre state != null + */ + protected void fireActionEvent(PageState state) { + ActionEvent e = null; + + for (Iterator i = m_actionListeners.iterator(); i.hasNext();) { + if (e == null) { + e = new ActionEvent(this, state); + } + + final ActionListener listener = (ActionListener) i.next(); + + if (s_log.isDebugEnabled()) { + s_log.debug("Firing action listener " + listener); + } + + listener.actionPerformed(e); + } + } + + /** + * Broadcasts a {@link RequestEvent} to all registered listeners. The source of the event is + * this page, and the state recorded in the event is the one resulting from processing the + * current request. + * + * @param state the state for this event + * + * @pre state != null + */ + protected void fireRequestEvent(PageState state) { + RequestEvent e = null; + + for (Iterator i = m_requestListeners.iterator(); i.hasNext();) { + if (e == null) { + e = new RequestEvent(this, state); + } + + final RequestListener listener = (RequestListener) i.next(); + + if (s_log.isDebugEnabled()) { + s_log.debug("Firing request listener " + listener); + } + + listener.pageRequested(e); + } + } + + /** + * Export page generator information if set. The m_pageGenerator is a HashMap containing the + * information as key value. In general this should include generator name and generator + * version. + * + * @param page parent element - should be bebeop:page + * + * @pre m_pageGenerator != null && !m_pageGenerator.isEmpty() + */ + final protected void exportSystemInformation(Element page) { + SystemInformation sysInfo = SystemInformation.getInstance(); + if (!sysInfo.isEmpty()) { + Element gen = page.newChildElement("bebop:systemInformation", BEBOP_XML_NS); + + Iterator> keyValues = sysInfo.iterator(); + while (keyValues.hasNext()) { + Map.Entry entry = keyValues.next(); + gen.addAttribute(entry.getKey(), entry.getValue()); + } + } + } + + // Client-side stylesheet storage + private class Stylesheet { + + String m_URI; + String m_type; + + public Stylesheet(String stylesheetURI, String mimeType) { + m_URI = stylesheetURI; + m_type = mimeType; + } + + public void generateXML(Element parent) { + Element style = parent.newChildElement("bebop:stylesheet", + BEBOP_XML_NS); + style.addAttribute("href", m_URI); + if (m_type != null) { + style.addAttribute("type", m_type); + } + } + + } + + /** + * Adds a component to the page model. + * + * @deprecated This method will become private in ACS 5.0. + */ + public void addComponent(Component c) { + Assert.isUnlocked(this); + + if (!stateContains(c)) { + if (c == null) { + s_log.error("c is null"); + } /*else { + s_log.error("c: " + c.toString()); + }*/ + + String key = c.getKey(); + if (key == null) { + key = Integer.toString(m_components.size()); + } + if (m_componentMap.get(key) != null) { + throw new IllegalArgumentException( + "Component key must not be duplicated. The key " + key + + " is shared by more than one component."); + } + m_componentMap.put(key, c); + m_components.add(c); + } + } + + /** + * Registers a state parameter for a component. It is permissible to register the same state + * parameter several times, from the same or different components. The name of the parameter + * will be changed to ensure that it won't clash with any other component's parameter. If the + * parameter is added more than once, the name is only changed the first time it is added. + * + * @param c the component to register the parameter for + * @param p the state parameter to register + * + * @see #addGlobalStateParam + * + * @pre stateContains(c) + * @pre ! isLocked() + * @pre p != null + */ + public void addComponentStateParam(Component c, ParameterModel p) { + Assert.isUnlocked(this); + + if (!stateContains(c)) { + throw new IllegalArgumentException( + "Component must be registered in Page"); + } + if (!m_stateModel.containsFormParam(p)) { + String name = parameterName(c, p.getName()); + s_log.debug(String.format("Setting name of parameter to add to '%s'", + name)); + p.setName(name); + m_stateModel.addFormParam(p); + + Collection params = (Collection) m_componentParameterMap.get(c); + if (params == null) { + params = new ArrayList(); + m_componentParameterMap.put(c, params); + } + params.add(p); + } + } + + /** + *

+ * Get the parameters registered for a given component.

+ */ + public Collection getComponentParameters(Component c) { + return (Collection) m_componentParameterMap.get(c); + } + + /** + * Gets the state index of a component. This is the number assigned to the component in the + * register traveral + * + * @param c the component to search for + * + * @return the index in this list of the first occurrence of the specified element, or -1 if + * this list does not contain this element. + * + * @pre c != null + * @post contains(c) implies (return >= 0) && (return < size()) + * @pos + * t !contains(c) implies return == -1 + */ + public int stateIndex(Component c) { + return m_components.indexOf(c); + } + + /** + * The number of components in the page model. + * + * @post return >= 0 + */ + public int stateSize() { + return m_components.size(); + } + + /** + * Checks whether this component is already in the page model. + * + * @pre c != null + */ + public boolean stateContains(Component c) { + return m_components.contains(c); + } + + /** + * Gets a page component by index. + * + * @pre (i >= 0) && (i < size()) + * @pos + * t return != null + */ + public Component getComponent(int i) { + return (Component) m_components.get(i); + } + + /** + * Gets a page component by key. + * + * @pre s != null + */ + Component getComponent(String s) { + return (Component) m_componentMap.get(s); + } + + /** + * Gets the form model that contains the parameters for the page's state. + */ + public final FormModel getStateModel() { + return m_stateModel; + } + + /** + * Gets the ParameterModels held in this Page. + * + * @return an iterator of ParameterModels. + */ + public Iterator getParameters() { + return m_stateModel.getParameters(); + } + + /** + * Checks whether the specified component is visible by default on the page. + * + * @param c a component contained in the page + * + * @return true if the component is visible by default; false + * otherwise. + * + * @see #setVisibleDefault setVisibleDefault + * @see Component#setVisible Component.setVisible + */ + public boolean isVisibleDefault(Component c) { + Assert.isTrue(stateContains(c)); + + return !m_invisible.get(stateIndex(c)); + } + + /** + * Sets whether the specified component is visible by default. The default visibility is used + * when a page is displayed for the first time and on subsequent requests until the visibility + * of a component is changed explicitly with {@link Component#setVisible + * Component.setVisible}. + * + *

+ * When a component is first added to a page, it is visible. + * + * @param c a component whose visibility is to be set + * @param v true if the component is visible; false otherwise. + * + * @see Component#setVisible Component.setVisible + * @see Component#register Component.register + */ + public void setVisibleDefault(Component c, boolean v) { + Assert.isUnlocked(this); + + addComponent(c); + int i = stateIndex(c); + if (v) { + m_invisible.clear(i); + } else { + m_invisible.set(i); + } + } + + /** + * The global name of the parameter name in the component c. + */ + public String parameterName(Component c, String name) { + if (c == null || !stateContains(c)) { + return name; + } + + return componentPrefix(c) + name; + } + + /** + * The global name of the parameter name. + */ + public String parameterName(String name) { + return parameterName(null, name); + } + + void reset(final PageState ps, Component cmpnt) { + Traversal resetter = new Traversal() { + @Override + protected void act(Component c) { + Collection cp = getComponentParameters(c); + if (cp != null) { + Iterator iter = cp.iterator(); + while (iter.hasNext()) { + ParameterModel p = (ParameterModel) iter.next(); + ps.setValue(p, null); + } + } + c.setVisible(ps, isVisibleDefault(c)); + } + + }; + resetter.preorder(cmpnt); + } + + /** + * Return the prefix that is prepended to each component's state parameters to keep them unique. + */ + private final String componentPrefix(Component c) { + if (c == null) { + return COMPONENT_PREFIX + "g" + DELIMITER; + } else { + // WRS: preferentially use key if it exists + String key = c.getKey(); + if (key == null) { + if (stateContains(c)) { + key = String.valueOf(stateIndex(c)); + } else { + throw new IllegalArgumentException( + "Cannot generate prefix for component: key is null " + + "and component " + c.toString() + "/" + c.getKey() + + " did not register with page."); + } + } + return COMPONENT_PREFIX + key + DELIMITER; + } + } + + /** + * Undo the name change that {@link #parameterName} does. + * + * @param name a possibly mangled name + * + * @return the unmangled name. + */ + private static final String unmangle(String name) { + if (!name.startsWith(COMPONENT_PREFIX)) { + return name; + } + // Find the second occurence of delimiter + int prefix = name.indexOf(DELIMITER, name.indexOf(DELIMITER) + 1); + if (prefix >= 0 && prefix < name.length()) { + return name.substring(prefix + 1); + } + return name; + } + + // Procs for debugging output + private static String NAME = "name"; + + /** + * Produces an XML fragment that captures the layout of this page. + */ + private void showStructure(PageState s, Element root) { + final HttpServletRequest req = s.getRequest(); + Element state = root.newChildElement("bebop:state", BEBOP_XML_NS); + // Selected component + String sel = req.getParameter(m_selected.getName()); + Element selected = state.newChildElement("bebop:selected", BEBOP_XML_NS); + + selected.addAttribute(NAME, m_selected.getName()); + selected.setText(sel); + + // Control event + Element eventName = state.newChildElement("bebop:eventName", BEBOP_XML_NS); + eventName.addAttribute(NAME, m_controlEvent.getName()); + eventName.setText(req.getParameter(m_controlEvent.getName())); + Element eventValue = state.newChildElement("bebop:eventValue", BEBOP_XML_NS); + eventValue.addAttribute(NAME, m_controlValue.getName()); + eventValue.setText(req.getParameter(m_controlValue.getName())); + + // Global parameters + Element globalState = root.newChildElement("bebop:params", BEBOP_XML_NS); + for (Iterator ii = getStateModel().getParameters(); ii.hasNext();) { + ParameterModel p = (ParameterModel) ii.next(); + if (!p.getName().startsWith(COMPONENT_PREFIX)) { + Element param = globalState.newChildElement("bebop:param", BEBOP_XML_NS); + param.addAttribute(NAME, p.getName()); + param.setText(String.valueOf(s.getValue(p))); + } + } + + showVisibility(s, this, root); + } + + /** + * @see showStructure(PageState, Element) + */ + private void showVisibility(PageState s, Component c, Element parent) { + HttpServletRequest req = s.getRequest(); + + Element cmp = parent.newChildElement("bebop:component", BEBOP_XML_NS); + cmp.addAttribute(NAME, getDebugLabel(c)); + cmp.addAttribute("idx", String.valueOf(stateIndex(c))); + cmp.addAttribute("isVisible", (s.isVisible(c) ? "yes" : "no")); + cmp.addAttribute("class", c.getClass().getName()); + + if (c.getKey() != null) { + String prefix = componentPrefix(c); + for (Iterator i = getStateModel().getParameters(); i.hasNext();) { + ParameterModel p = (ParameterModel) i.next(); + if (!p.getName().startsWith(prefix)) { + continue; + } + + Element param = parent.newChildElement("bebop:param", BEBOP_XML_NS); + param.addAttribute(NAME, unmangle(p.getName())); + param.addAttribute("defaultValue", + String.valueOf(req.getParameter(p.getName()))); + param.addAttribute("currentValue", String.valueOf(s.getValue(p))); + } + } + for (Iterator i = c.children(); i.hasNext();) { + showVisibility(s, ((Component) i.next()), cmp); + } + } + + private static String getDebugLabel(Component c) { + if (c.getKey() != null) { + return c.getKey(); + } + + String klass = c.getClass().getName(); + return klass.substring(klass.lastIndexOf(".") + 1, klass.length()); + } + + /** + * return a string that represents an ordered list of component ids used on the page. For + * situations where only the components present is of importance, this may be used by + * implementations of hashCode & equals + * + * @return + */ + public String getComponentString() { + Iterator it = m_componentMap.keySet().iterator(); + /*int hash = 0; + while (it.hasNext()) { + String componentId = (String)it.next(); + s_log.debug("component id = " + componentId); + hash = hash | componentId.hashCode(); + s_log.debug("hash so far = " + hash); + }*/ + Date start = new Date(); + + StringBuilder hashString = new StringBuilder(); + while (it.hasNext()) { + String componentId = (String) it.next(); + hashString.append(componentId); + } + s_log.debug("Time to create hashCode for page: " + (new Date().getTime() - start. + getTime())); + return hashString.toString(); + + } + } diff --git a/ccm-core/src/com/arsdigita/core/Initializer.java b/ccm-core/src/com/arsdigita/core/Initializer.java index cac3316e6..106eb44fa 100755 --- a/ccm-core/src/com/arsdigita/core/Initializer.java +++ b/ccm-core/src/com/arsdigita/core/Initializer.java @@ -190,7 +190,7 @@ public class Initializer extends CompoundInitializer { }); // Set system informations - loadSystemInformation(); +// loadSystemInformation(); // register the document converters Converter converter = new PDFConverter(); @@ -229,14 +229,14 @@ public class Initializer extends CompoundInitializer { s_log.info("Core init(DomainInitEvent) done"); } - private void loadSystemInformation() { - SystemInformation sysInfo = SystemInformation.getInstance(); - - // Hardcoded for now - sysInfo.put("version", "v2.1.0"); - sysInfo.put("appname", "ScientificCMS"); - sysInfo.put("apphomepage", "http://www.scientificcms.org"); - sysInfo.lock(); - } +// private void loadSystemInformation() { +// SystemInformation sysInfo = SystemInformation.getInstance(); +// +// // Hardcoded for now +// sysInfo.put("version", "v2.3.x-SNAPSHOT"); +// sysInfo.put("appname", "ScientificCMS"); +// sysInfo.put("apphomepage", "http://www.scientificcms.org"); +// sysInfo.lock(); +// } } diff --git a/ccm-core/src/com/arsdigita/kernel/KernelConfig_parameter.properties b/ccm-core/src/com/arsdigita/kernel/KernelConfig_parameter.properties index 996cfb321..0db71c6a2 100755 --- a/ccm-core/src/com/arsdigita/kernel/KernelConfig_parameter.properties +++ b/ccm-core/src/com/arsdigita/kernel/KernelConfig_parameter.properties @@ -2,35 +2,43 @@ waf.debug.title=Global debug flag waf.debug.purpose=Enables or disables WAF debugging waf.debug.example=true waf.debug.format=true|false + waf.kernel.data_permission_check_enabled.title=DML permission checking flag waf.kernel.data_permission_check_enabled.purpose=Enables or disables permissions checks on database writes waf.kernel.data_permission_check_enabled.example=true waf.kernel.data_permission_check_enabled.format=true|false + waf.kernel.primary_user_identifier.title=The primary user identification waf.kernel.primary_user_identifier.purpose=Determines whether email addresses or screen names are used to authenticate users waf.kernel.primary_user_identifier.example=email waf.kernel.primary_user_identifier.format=email|screen_name + waf.kernel.remember_login.title=Remember login by default waf.kernel.remember_login.purpose=Determines whether the "remember login" feature is enabled or disabled by default waf.kernel.remember_login.example=true waf.kernel.remember_login.format=true|false + waf.kernel.secure_login.title=Require secure login waf.kernel.secure_login.purpose=Accept only credentials presented over secure connection waf.kernel.secure_login.example=true waf.kernel.secure_login.format=true|false + waf.kernel.sso_login.title=Enable SSO login waf.kernel.sso_login.purpose=Enable alternative "RegisterSSO" login context. waf.kernel.sso_login.example=false waf.kernel.sso_login.format=true|false + waf.kernel.supported_languages.title=Set the supported languages for categorization waf.kernel.supported_languages.purpose=Set the supported languages for categorization. First entry is the default language waf.kernel.supported_languages.example=en,de,fr,nl,it,pt,es waf.kernel.supported_languages.format=[string] + waf.kernel.language_independent_items.title=Allow language independent content items waf.kernel.language_independent_items.purpose=Allow language independent content items waf.kernel.language_independent_items.example=false waf.kernel.language_independent_items.format=true|false + waf.kernel.language_independent_code.title=Select language independent code waf.kernel.language_independent_code.purpose=Allow language independent code waf.kernel.language_independent_code.example=-- -waf.kernel.language_independent_code.format=[string] +waf.kernel.language_independent_code.format=[string] \ No newline at end of file diff --git a/ccm-core/src/com/arsdigita/util/SystemInformation.java b/ccm-core/src/com/arsdigita/util/SystemInformation.java index b73560763..60c804927 100644 --- a/ccm-core/src/com/arsdigita/util/SystemInformation.java +++ b/ccm-core/src/com/arsdigita/util/SystemInformation.java @@ -4,63 +4,84 @@ */ package com.arsdigita.util; +import com.arsdigita.runtime.AbstractConfig; +import com.arsdigita.util.parameter.Parameter; +import com.arsdigita.util.parameter.StringParameter; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.Set; /** * * @author Sören Bernstein + * @author Jens Pelzetter */ -public class SystemInformation implements Lockable { +public class SystemInformation extends AbstractConfig { //implements Lockable { - private Map systemInformation = new HashMap(); - private boolean locked = false; + private Parameter sysInfoParam = new StringParameter( + "ccm.systeminformation", + Parameter.REQUIRED, + "version::2.x.y; appname::LibreCCM; apphomepage::http://www.libreccm.org;"); + + private Map systemInformation;// = new HashMap(); + //private boolean locked = false; /** * The one and only instance of this class */ - private static final SystemInformation INSTANCE = new SystemInformation(); + private static SystemInformation INSTANCE;// = new SystemInformation(); - private SystemInformation() { - // Nothing + public SystemInformation() { + register(sysInfoParam); + + loadInfo(); } /** * @return The instance of this class. */ public static SystemInformation getInstance() { - return SystemInformation.INSTANCE; - } - - /** - * Put system information into the map. If this instance is locked, this method - * throw an {@link AssertionError}. - * - * @param key Key for the Map. Also used as attribute name during output. - * @param value Value - * @throws IllegalArgumentException if key or value is null or empty - */ - final public void put(String key, String value) throws IllegalArgumentException { - if (key == null || key.isEmpty()) { - throw new IllegalArgumentException("Parameter key must not be null or empty."); - } - if (value == null || value.isEmpty()) { - throw new IllegalArgumentException("Parameter value must not be null or empty."); - } - // Test if instance is not locked - Assert.isUnlocked(this); - systemInformation.put(key, value); + if (INSTANCE == null) { + INSTANCE = new SystemInformation(); + INSTANCE.load(); + } + + return INSTANCE; } +// /** +// * Put system information into the map. If this instance is locked, this method throw an +// * {@link AssertionError}. +// * +// * @param key Key for the Map. Also used as attribute name during output. +// * @param value Value +// * +// * @throws IllegalArgumentException if key or value is null or empty +// */ +// final public void put(final String key, final String value) throws IllegalArgumentException { +// if (key == null || key.isEmpty()) { +// throw new IllegalArgumentException("Parameter key must not be null or empty."); +// } +// if (value == null || value.isEmpty()) { +// throw new IllegalArgumentException("Parameter value must not be null or empty."); +// } +// // Test if instance is not locked +// Assert.isUnlocked(this); +// systemInformation.put(key, value); +// } /** * Get system informations by key. - * + * * @param key Key for the map + * * @return value for key + * * @throws IllegalArgumentException if key is null or empty */ final public String get(String key) throws IllegalArgumentException { + if (systemInformation == null) { + loadMap(); + } + if (key == null || key.isEmpty()) { throw new IllegalArgumentException("Parameter key must not be null or empty."); } @@ -69,32 +90,59 @@ public class SystemInformation implements Lockable { /** * Get iterator of this map. - * + * * @return iterator of map */ final public Iterator> iterator() { - return ((Set>) systemInformation.entrySet()).iterator(); - } - - /** - * - * @return - */ - final public boolean isEmpty() { - return systemInformation.isEmpty(); - } - /** - * Lock this instance to prevent further changes. - */ - final public void lock() { - locked = true; + if (systemInformation == null) { + loadMap(); + } + + return (systemInformation.entrySet()).iterator(); } /** - * Test, if this instance is locked. - * @return locked + * + * @return */ - final public boolean isLocked() { - return locked; + final public boolean isEmpty() { + if (systemInformation == null) { + loadMap(); + } + + return systemInformation.isEmpty(); + } + + /** + * Lock this instance to prevent further changes. + */ +// final public void lock() { +// locked = true; +// } +// +// /** +// * Test, if this instance is locked. +// * +// * @return locked +// */ +// final public boolean isLocked() { +// return locked; +// } + private void loadMap() { + systemInformation = new HashMap(); + + final String[] tokens = ((String) get(sysInfoParam)).split(";"); + for (String token : tokens) { + processToken(token); + } + } + + private void processToken(final String token) { + final String[] parts = token.split("::"); + if (2 == parts.length) { + systemInformation.put(parts[0].trim(), parts[1].trim()); + } + } + } diff --git a/ccm-sci-publications/application.xml b/ccm-sci-publications/application.xml index 2492882f0..ce166cb3a 100644 --- a/ccm-sci-publications/application.xml +++ b/ccm-sci-publications/application.xml @@ -2,7 +2,7 @@ diff --git a/ccm-sci-publications/pdl/com/arsdigita/content-types/Publication.pdl b/ccm-sci-publications/pdl/com/arsdigita/content-types/Publication.pdl index 27a106995..289fc619b 100644 --- a/ccm-sci-publications/pdl/com/arsdigita/content-types/Publication.pdl +++ b/ccm-sci-publications/pdl/com/arsdigita/content-types/Publication.pdl @@ -26,8 +26,8 @@ import com.arsdigita.cms.ContentBundle; object type Publication extends ContentPage { Integer[0..1] yearOfPublication = ct_publications.year INTEGER; - String[0..1] abstract = ct_publications.abstract VARCHAR(4096); - String[0..1] misc = ct_publications.misc VARCHAR(4096); + String[0..1] abstract = ct_publications.abstract CLOB; + String[0..1] misc = ct_publications.misc CLOB; //The reviewed property has been moved here for performance reasons. It //is necessary to have access to this property from a data query //over all publications of a person. Since this property was only diff --git a/ccm-sci-publications/sql/ccm-sci-publications/default/upgrade/6.6.6-6.6.7/abstract_to_text.sql b/ccm-sci-publications/sql/ccm-sci-publications/default/upgrade/6.6.6-6.6.7/abstract_to_text.sql new file mode 100644 index 000000000..51a858d4c --- /dev/null +++ b/ccm-sci-publications/sql/ccm-sci-publications/default/upgrade/6.6.6-6.6.7/abstract_to_text.sql @@ -0,0 +1,3 @@ +-- Alter abstract and misc column type to text +ALTER TABLE ct_publications ALTER COLUMN abstract TYPE text; +ALTER TABLE ct_publications ALTER COLUMN misc TYPE text; \ No newline at end of file diff --git a/ccm-sci-publications/sql/ccm-sci-publications/upgrade/postgres-6.6.6-6.6.7.sql b/ccm-sci-publications/sql/ccm-sci-publications/upgrade/postgres-6.6.6-6.6.7.sql new file mode 100644 index 000000000..94fbd377c --- /dev/null +++ b/ccm-sci-publications/sql/ccm-sci-publications/upgrade/postgres-6.6.6-6.6.7.sql @@ -0,0 +1,8 @@ +\echo 'ScientificCMS Publications module 6.6.6 -> 6.6.7 Upgrade script (PostgreSQL)' + +begin; + +\i ../default/upgrade/6.6.6-6.6.7/abstract_to_text.sql + +end; + diff --git a/ccm-sci-publications/src/ccm-sci-publications.upgrade b/ccm-sci-publications/src/ccm-sci-publications.upgrade index d009d708d..1bd6ab285 100644 --- a/ccm-sci-publications/src/ccm-sci-publications.upgrade +++ b/ccm-sci-publications/src/ccm-sci-publications.upgrade @@ -18,4 +18,7 @@