Improvded error handling for ContentItemPortlet

git-svn-id: https://svn.libreccm.org/ccm/trunk@3079 8810af33-2d31-482b-a856-94f89814c4df
master
jensp 2015-01-15 16:03:15 +00:00
parent 8cb473a69f
commit c431141540
2 changed files with 165 additions and 182 deletions

View File

@ -19,6 +19,7 @@
package com.arsdigita.cms.ui.portlet;
import com.arsdigita.bebop.ColumnPanel;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
@ -42,6 +43,7 @@ import com.arsdigita.cms.dispatcher.CMSDispatcher;
import com.arsdigita.cms.dispatcher.ItemResolver;
import com.arsdigita.cms.dispatcher.MultilingualItemResolver;
import com.arsdigita.cms.portlet.ContentItemPortlet;
import com.arsdigita.globalization.GlobalizedMessage;
import java.net.MalformedURLException;
import java.util.StringTokenizer;
@ -178,8 +180,9 @@ public class ContentItemPortletEditor extends PortletConfigFormSection {
super.validateWidgets(state, portlet);
Object item = m_contentItem.get( state );
if (item == null)
throw new FormProcessException("cannot find content item");
if (item == null) {
throw new FormProcessException(new GlobalizedMessage("Can't find content item"));
}
}
public void processWidgets(PageState state,

View File

@ -36,50 +36,34 @@ import java.util.Iterator;
import org.apache.log4j.Logger;
/**
* Represents the visual structure of an HTML form. Forms can be constructed
* with a Container argument to specify the type of layout this form will
* adhere to. The default is a column panel.
* Represents the visual structure of an HTML form. Forms can be constructed with a Container
* argument to specify the type of layout this form will adhere to. The default is a column panel.
*
* <p> As an example, a form that accepts a first and last name may be set
* up as follows:
* <p>
* As an example, a form that accepts a first and last name may be set up as follows:
*
* <pre style="background: #cccccc">
* public class MyForm extends Form
* implements FormProcessListener {
* public class MyForm extends Form implements FormProcessListener {
*
* private Text m_firstName;
* private Text m_lastName;
* private Text m_firstName; private Text m_lastName;
*
* public MyForm() {
* super("myform");
* add(new Label("First Name:"));
* m_firstName = new Text("firstName");
* m_firstName.setDefaultValue("John");
* add(m_firstName);
* public MyForm() { super("myform"); add(new Label("First Name:")); m_firstName = new
* Text("firstName"); m_firstName.setDefaultValue("John"); add(m_firstName);
*
* add(new Label("Last Name:"));
* m_lastName = new Text("lastName");
* m_lastName.setDefaultValue("Doe");
* m_lastName.addValidationListener(new NotNullValidationListener
* ("The last name"));
* add(m_lastName);
* add(new Label("Last Name:")); m_lastName = new Text("lastName");
* m_lastName.setDefaultValue("Doe"); m_lastName.addValidationListener(new NotNullValidationListener
* ("The last name")); add(m_lastName);
*
* add(new Submit("save", "Save"));
* addProcessListener(this);
* }
* add(new Submit("save", "Save")); addProcessListener(this); }
*
* public void process(FormSectionEvent e) {
* PageState s = e.getPageState();
* public void process(FormSectionEvent e) { PageState s = e.getPageState();
*
* System.out.println("You are " + m_firstName.getValue(s)
* + " " + m_lastName.getValue(s));
* }
* }
* System.out.println("You are " + m_firstName.getValue(s) + " " + m_lastName.getValue(s)); } }
* </pre>
*
* <p> This form automatically checks that the user supplied a last name. Only
* then does it call the <code>process</code> method, which prints the
* user-supplied values.
* <p>
* This form automatically checks that the user supplied a last name. Only then does it call the
* <code>process</code> method, which prints the user-supplied values.
*
* @author Karl Goldstein
* @author Uday Mathur
@ -91,27 +75,24 @@ import org.apache.log4j.Logger;
*/
public class Form extends FormSection implements BebopConstants {
/** Internal logger instance to faciliate debugging. Enable logging output
* by editing /WEB-INF/conf/log4j.properties int hte runtime environment
* and set com.arsdigita.bebop.Form=DEBUG by uncommenting
* or adding the line. */
/**
* Internal logger instance to faciliate debugging. Enable logging output by editing
* /WEB-INF/conf/log4j.properties int hte runtime environment and set
* com.arsdigita.bebop.Form=DEBUG by uncommenting or adding the line.
*/
private static final Logger s_log = Logger.getLogger(Form.class);
/**
* Constant for specifying a <code>get</code> submission method for this
* form. See the <a href=
* "http://www.w3.org/TR/html4/interact/forms.html#submit-format">W3C
* HTML specification</a> for a description of what this attribute
* does.
* Constant for specifying a <code>get</code> submission method for this form. See the <a href=
* "http://www.w3.org/TR/html4/interact/forms.html#submit-format">W3C HTML specification</a> for
* a description of what this attribute does.
*/
public final static String GET = "get";
/**
* Constant for specifying a <code>post</code> submission method for this
* form. See the <a href=
* "http://www.w3.org/TR/html4/interact/forms.html#submit-format">W3C HTML
* specification</a> for a description of what this attribute does.
* Constant for specifying a <code>post</code> submission method for this form. See the <a href=
* "http://www.w3.org/TR/html4/interact/forms.html#submit-format">W3C HTML specification</a> for
* a description of what this attribute does.
*/
public final static String POST = "post";
@ -134,18 +115,15 @@ public class Form extends FormSection implements BebopConstants {
private RequestLocal m_formData;
/**
* Determines whether or not a form is 'redirecting', meaning that
* it will clear the control event and redirect to the resulting
* state after form processing, so that a page reload won't cause
* the form to be resubmitted.
* Determines whether or not a form is 'redirecting', meaning that it will clear the control
* event and redirect to the resulting state after form processing, so that a page reload won't
* cause the form to be resubmitted.
*/
private boolean m_isRedirecting = false;
/**
* Constructs a new form with the specified name.
* At the time of creation, instantiates a new form model for the form and
* instantiates a default ColumnPanel to contain the components.
* Constructs a new form with the specified name. At the time of creation, instantiates a new
* form model for the form and instantiates a default ColumnPanel to contain the components.
*
* @param name the name of the form
*/
@ -154,10 +132,9 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Constructs a new form with the specified name and container. At the time
* of creation, instantiates a new form model for the form and replaces
* the default ColumnPanel with the specified container as the implicit
* container of the components.
* Constructs a new form with the specified name and container. At the time of creation,
* instantiates a new form model for the form and replaces the default ColumnPanel with the
* specified container as the implicit container of the components.
*
* @param name the name attribute of the form
* @param panel the implicit container that will hold the components
@ -170,29 +147,29 @@ public class Form extends FormSection implements BebopConstants {
addMagicTag();
}
/**
* Writes the output to a DOM to be used with the XSLT template to produce
* the appropriate output. If the form is not visible, no output is
* generated.
* Writes the output to a DOM to be used with the XSLT template to produce the appropriate
* output. If the form is not visible, no output is generated.
*
* <p>Generates a DOM fragment:
* <p><code><pre>
* <p>
* Generates a DOM fragment:
* <p>
* <code><pre>
* &lt;bebop:form action=%url; %bebopAttr;>
* .. XML for panel ..
* .. XML for page state ..
* &lt;/bebop:form>
* </pre></code>
*
* @param s the page state used to determine the values of form
* widgets and page state attributes
* @param parent the XML element to which the form adds its XML
* representation
* @param s the page state used to determine the values of form widgets and page state
* attributes
* @param parent the XML element to which the form adds its XML representation
*
* @see PageState#generateXML
*/
@Override
public void generateXML(PageState s, Element parent) {
if ( isVisible(s) ) {
if (isVisible(s)) {
Element form = generateXMLSansState(s, parent);
s.setControlEvent(this);
@ -202,11 +179,12 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Generates the XML representing the form and its widgets, but not the
* state information from <code>s</code>.
* Generates the XML representing the form and its widgets, but not the state information from
* <code>s</code>.
*
* @param s represents the curent request
* @param parent
*
* @return the top-level element for the form
*/
protected Element generateXMLSansState(PageState s, Element parent) {
@ -215,7 +193,6 @@ public class Form extends FormSection implements BebopConstants {
// Encode the URL with the servlet session information;
// do not use DispatcherHelper.encodeURL because the
// ACS global parameters are provided via the FormData.
String url = null;
if (m_action == null) {
@ -248,21 +225,25 @@ public class Form extends FormSection implements BebopConstants {
*/
protected void generateErrors(PageState ps, Element parent) {
for (Iterator it = getFormData(ps).getErrors(); it.hasNext(); ) {
for (Iterator it = getFormData(ps).getErrors(); it.hasNext();) {
Element errors = parent.newChildElement(BEBOP_FORMERRORS,
BEBOP_XML_NS);
Object msg = it.next();
if (msg == null) {
errors.addAttribute("message", "Unknown error");
} else {
errors.addAttribute("message",
(String)((GlobalizedMessage) it.next()).localize
(ps.getRequest())
);
(String) ((GlobalizedMessage) msg).localize(ps.getRequest()));
}
errors.addAttribute("id", getName());
}
}
/**
* <p>Determine whether or not this Form will redirect after its
* process listeners are fired.</p>
* <p>
* Determine whether or not this Form will redirect after its process listeners are fired.</p>
*
* @return
*/
@ -271,11 +252,9 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Setting the redirecting flag will cause the Form to clear the
* control event and redirect back to the current URL, after
* firing all process listeners. Doing so means that a user reload
* will not cause the form to be resubmitted. The default value for
* this flag is false.
* Setting the redirecting flag will cause the Form to clear the control event and redirect back
* to the current URL, after firing all process listeners. Doing so means that a user reload
* will not cause the form to be resubmitted. The default value for this flag is false.
*
* @param isRedirecting
*/
@ -285,11 +264,13 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Responds to the request by processing this form with the HTTP request
* given in <code>state</code>.
* Responds to the request by processing this form with the HTTP request given in
* <code>state</code>.
*
* @see #process process(...)
*
* @param state represents the current request
*
* @throws javax.servlet.ServletException
*/
@Override
@ -306,11 +287,11 @@ public class Form extends FormSection implements BebopConstants {
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Methods to set the HTML attributes of the FORM element
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* Sets the <code>name</code> attribute for the form.
*
* @param name the name for the form
*
* @pre ! isLocked()
*/
public void setName(String name) {
@ -328,11 +309,11 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Sets the <code>enctype</code> attribute used in the
* <code>form</code> element. No encoding type is specified by
* default.
* Sets the <code>enctype</code> attribute used in the <code>form</code> element. No encoding
* type is specified by default.
*
* @param encType the encoding type
*
* @pre ! isLocked()
*/
public void setEncType(String encType) {
@ -341,12 +322,11 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Sets the <code>onSubmit</code> attribute used in the
* <code>form</code> element. No onsubmit handler is specified by
* default.
* Sets the <code>onSubmit</code> attribute used in the <code>form</code> element. No onsubmit
* handler is specified by default.
*
* @param javascriptCode the javascript code associated with this attribute
*
* @param javascriptCode the javascript code associated with this
* attribute
* @pre ! isLocked()
*/
public void setOnSubmit(String javascriptCode) {
@ -355,12 +335,11 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Sets the <code>ONRESET</code> attribute used in the
* <code>FORM</code> element. No onreset handler is specified by
* default.
* Sets the <code>ONRESET</code> attribute used in the <code>FORM</code> element. No onreset
* handler is specified by default.
*
* @param javascriptCode the javascript code associated with this attribute
*
* @param javascriptCode the javascript code associated with this
* attribute
* @pre ! isLocked()
*/
public void setOnReset(String javascriptCode) {
@ -372,6 +351,7 @@ public class Form extends FormSection implements BebopConstants {
* Sets the HTTP method used to submit the form.
*
* @param method either <code>GET</code> or <code>POST</code>
*
* @pre ! isLocked()
*/
public void setMethod(String method) {
@ -384,12 +364,10 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Returns true if form processing is turned on when the form is
* invisible.
* Returns true if form processing is turned on when the form is invisible.
*
* @return true if the form listeners should be
* processed even when the form is not visible on the page,
* false otherwise
* @return true if the form listeners should be processed even when the form is not visible on
* the page, false otherwise
*/
protected boolean getProcessInvisible() {
return m_processInvisible;
@ -398,24 +376,24 @@ public class Form extends FormSection implements BebopConstants {
/**
* Turns form processing on/off when the form is invisible.
*
* @param processInvisible true if the form listeners should be
* processed even when the form is not visible on the page
* @param processInvisible true if the form listeners should be processed even when the form is
* not visible on the page
*/
protected void setProcessInvisible(boolean processInvisible) {
m_processInvisible = processInvisible;
}
/**
* Sets the URL for the form's <code>action</code> attribute. This
* is the URL to which submissions will be sent when the user
* clicks a submit button on the form. By default, the action is
* <code>null</code>, instructing the form to set the action to
* the URL of the page in which it is used. If the action is set
* to a different URL, none of the listeners registered with this
* form will be run.
* Sets the URL for the form's <code>action</code> attribute. This is the URL to which
* submissions will be sent when the user clicks a submit button on the form. By default, the
* action is <code>null</code>, instructing the form to set the action to the URL of the page in
* which it is used. If the action is set to a different URL, none of the listeners registered
* with this form will be run.
*
* @param action the URL to submit this form to
* @pre ! isLocked() */
*
* @pre ! isLocked()
*/
public void setAction(String action) {
Assert.isUnlocked(this);
m_action = action;
@ -425,22 +403,24 @@ public class Form extends FormSection implements BebopConstants {
* Returns the URL for the form's <code>action</code> attribute.
*
* @return the URL to which to submit this form.
*
* @see #setAction setAction
*/
public final String getAction(){
public final String getAction() {
return m_action;
}
/**
* Processes this form, creating a <code>FormData</code> object. Runs the
* right set of init, validation, and process listeners, depending on
* whether this is an initial request to the form and whether the form
* submission was valid. Submission listeners are always run.
* Processes this form, creating a <code>FormData</code> object. Runs the right set of init,
* validation, and process listeners, depending on whether this is an initial request to the
* form and whether the form submission was valid. Submission listeners are always run.
*
* @see #getFormData
*
* @param state represents the current request
* @return the values extracted from the HTTP request contained
* in <code>state</code>.
*
* @return the values extracted from the HTTP request contained in <code>state</code>.
*
* @throws com.arsdigita.bebop.FormProcessException
* @pre state != null
* @post return != null
@ -461,14 +441,14 @@ public class Form extends FormSection implements BebopConstants {
/**
* Returns the form data constructed by the {@link #process
* process} method for the request described by
* <code>state</code>. Processes the form if it has not already
* been processed.
* process} method for the request described by <code>state</code>. Processes the form if it has
* not already been processed.
*
* @param state describes the current request
* @return the values extracted from the HTTP request contained
* in <code>state</code>, or <code>null</code> if the form has not been
* processed yet.
*
* @return the values extracted from the HTTP request contained in <code>state</code>, or
* <code>null</code> if the form has not been processed yet.
*
* @pre state != null
* @post return != null
*/
@ -476,10 +456,9 @@ public class Form extends FormSection implements BebopConstants {
return (FormData) m_formData.get(state);
}
/**
* Adds a Hidden Tag to this form so that our controller can determine if
* this is an initial request.
* Adds a Hidden Tag to this form so that our controller can determine if this is an initial
* request.
*/
protected void addMagicTag() {
Hidden h = new Hidden(getModel().getMagicTagName());
@ -488,30 +467,30 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Traverses the components contained in this form, collecting
* parameterModels and Listeners into this form's FormModel.
* Traverses the components contained in this form, collecting parameterModels and Listeners
* into this form's FormModel.
*/
protected void traverse() {
Traversal formRegistrar = new Traversal() {
@Override
protected void act(Component c) {
if ( c == Form.this ) {
if (c == Form.this) {
return;
}
if ( c instanceof Form ) {
throw new IllegalStateException
("Forms cannot contain other Forms");
if (c instanceof Form) {
throw new IllegalStateException("Forms cannot contain other Forms");
}
c.register(Form.this, getModel());
}
};
formRegistrar.preorder(this);
}
/**
* Adds this form to the page and traverses the components contained in
* this form, collecting parameterModels and Listeners into this form's
* FormModel.
* Adds this form to the page and traverses the components contained in this form, collecting
* parameterModels and Listeners into this form's FormModel.
*
* @param p page in which to register this form
*/
@ -523,6 +502,7 @@ public class Form extends FormSection implements BebopConstants {
/**
* TODO
*
* @param model
*/
public void excludeParameterFromExport(ParameterModel model) {
@ -530,12 +510,12 @@ public class Form extends FormSection implements BebopConstants {
}
/**
* Initialize <code>m_formData</code> so that accessing the per-request
* form data forces the form to be processed on the first access and
* caches the form data for subsequent requests.
* Initialize <code>m_formData</code> so that accessing the per-request form data forces the
* form to be processed on the first access and caches the form data for subsequent requests.
*/
private void initFormData() {
m_formData = new RequestLocal() {
@Override
protected Object initialValue(PageState s) {
// TODO: We need to come up with the right strategy for
@ -549,6 +529,7 @@ public class Form extends FormSection implements BebopConstants {
+ e.getMessage(), e);
}
}
};
}
@ -559,15 +540,13 @@ public class Form extends FormSection implements BebopConstants {
*/
@Override
public String toString() {
return super.toString() + " " +
"[" + getName() + "," + getAction() + "," + getMethod() + "," +
isRedirecting() + "]";
return super.toString() + " " + "[" + getName() + "," + getAction() + "," + getMethod()
+ "," + isRedirecting() + "]";
}
/**
* Protected access to set the formdata request local.
* This method is required if a subclass wishes to override the
* process method.
* Protected access to set the formdata request local. This method is required if a subclass
* wishes to override the process method.
*
* @param state
* @param data
@ -575,4 +554,5 @@ public class Form extends FormSection implements BebopConstants {
protected void setFormData(PageState state, FormData data) {
m_formData.set(state, data);
}
}