It's very common that the objects underpinning specialized use
cases have custom ComponentFactorys so that they
are rendered in a particular way. This is the case for
ClaimWizard (see Section 2.8, “Specialized Use Cases”); for
ClaimExpenseSummary the specialized view is
provided by the googlecharts custom component (see Section 5.3, “Google Charts”).
It's good practice to create a new Maven submodule for any custom
components; you'll find this component in the
claims-ui module.
package org.nakedobjects.examples.claims.ui.claimwizard;
import org.apache.wicket.Component;
import org.apache.wicket.model.IModel;
import org.nakedobjects.examples.claims.dom.claim.ClaimWizard;
import org.nakedobjects.metamodel.spec.NakedObjectSpecification;
import org.starobjects.wicket.viewer.components.ComponentType;
import org.starobjects.wicket.viewer.components.entity.EntityComponentFactoryAbstract;
import org.starobjects.wicket.viewer.components.entity.EntityModel;
public class ClaimWizardComponentFactory extends EntityComponentFactoryAbstract {
private static final long serialVersionUID = 1L;
private static final String NAME = "wizard";
public ClaimWizardComponentFactory() {
super(ComponentType.ENTITY, NAME);
}
@Override
protected ApplicationAdvice appliesTo(IModel<?> model) {
return appliesExclusivelyIf(super.appliesTo(model).applies() && isModelForWizard((EntityModel)model));
}
private boolean isModelForWizard(EntityModel model) {
final NakedObjectSpecification typeOfSpec = model.getTypeOfSpecification();
final NakedObjectSpecification claimWizardSpec = getSpecificationLoader().loadSpecification(ClaimWizard.class);
return typeOfSpec.isOfType(claimWizardSpec);
}
@Override
public Component createComponent(String id, IModel<?> model) {
final EntityModel entityModel = (EntityModel)model;
return new ClaimWizardPanel(id, entityModel);
}
}package org.nakedobjects.examples.claims.ui.claimwizard;
import java.util.List;
import org.apache.wicket.Session;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.validation.AbstractFormValidator;
import org.apache.wicket.markup.html.panel.ComponentFeedbackPanel;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.Model;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.commons.filters.Filter;
import org.nakedobjects.metamodel.facets.object.validate.ValidateObjectFacet;
import org.nakedobjects.metamodel.spec.NakedObjectSpecification;
import org.nakedobjects.metamodel.spec.feature.NakedObjectAssociation;
import org.nakedobjects.metamodel.spec.feature.NakedObjectAssociationFilters;
import org.nakedobjects.metamodel.spec.feature.OneToOneAssociation;
import org.starobjects.wicket.viewer.common.ProcessObjectPanelAbstract;
import org.starobjects.wicket.viewer.common.scalars.ScalarModel;
import org.starobjects.wicket.viewer.components.ComponentType;
import org.starobjects.wicket.viewer.components.entity.EntityModel;
import org.starobjects.wicket.viewer.mementos.PropertyMemento;
import org.starobjects.wicket.viewer.util.Mementos;
import com.google.common.collect.Lists;
public class ClaimWizardPanel extends ProcessObjectPanelAbstract {
private static final long serialVersionUID = 1L;
private static final String ID_CLAIM_WIZARD_PROPERTIES_FORM = "claimWizardPropertiesForm";
private static final String ID_PROPERTIES = "properties";
public ClaimWizardPanel(String id, EntityModel model) {
super(id, model);
buildGui();
}
private ClaimWizardForm claimWizardForm;
private void buildGui() {
EntityModel entityModel = getModel();
entityModel.toEditMode();
claimWizardForm = new ClaimWizardForm(ID_CLAIM_WIZARD_PROPERTIES_FORM,
getModel());
addOrReplace(claimWizardForm);
}
class ClaimWizardForm extends Form<NakedObject> {
private static final long serialVersionUID = 1L;
private static final String ID_FEEDBACK = "feedback";
private static final String ID_PREVIOUS = "previous";
private static final String ID_NEXT = "next";
private static final String ID_FINISH = "finish";
private static final String PREVIOUS_ACTION_ID = "previous()";
private static final String NEXT_ACTION_ID = "next()";
private static final String FINISH_ACTION_ID = "finish()";
private FeedbackPanel feedback;
public ClaimWizardForm(String id, EntityModel entityModel) {
super(id, entityModel);
buildFormGui();
}
private void buildFormGui() {
addProperties();
addButtons();
addFeedbackGui();
addValidator();
}
private void addProperties() {
EntityModel entityModel = (EntityModel) getModel();
NakedObject adapter = entityModel.getObject();
NakedObjectSpecification noSpec = adapter.getSpecification();
List<OneToOneAssociation> properties = visibleProperties(adapter,
noSpec);
RepeatingView rv = new RepeatingView(ID_PROPERTIES);
add(rv);
List<PropertyMemento> mementos = buildPropertyMementos(properties);
for (PropertyMemento pm : mementos) {
WebMarkupContainer container = new WebMarkupContainer(rv
.newChildId());
rv.add(container);
ScalarModel scalarModel = entityModel.getPropertyModel(pm);
getComponentFactoryRegistry().addOrReplaceComponent(container,
ComponentType.SCALAR, scalarModel);
}
}
@SuppressWarnings("unchecked")
private List<OneToOneAssociation> visibleProperties(
NakedObject adapter, NakedObjectSpecification noSpec) {
return (List<OneToOneAssociation>) noSpec
.getAssociationList(visiblePropertyFilter(adapter));
}
private Filter<NakedObjectAssociation> visiblePropertyFilter(
NakedObject adapter) {
return NakedObjectAssociationFilters.PROPERTIES
.and(NakedObjectAssociationFilters.dynamicallyVisible(
getAuthenticationSession(), adapter));
}
private List<PropertyMemento> buildPropertyMementos(
List<OneToOneAssociation> properties) {
List<PropertyMemento> transform = Lists.transform(properties,
Mementos.fromProperty());
// we copy into a new array list otherwise we get lazy evaluation =
// reference to a non-serializable object
return Lists.newArrayList(transform);
}
private void addButtons() {
add(createButton(ID_PREVIOUS, "Previous", PREVIOUS_ACTION_ID));
add(createButton(ID_NEXT, "Next", NEXT_ACTION_ID));
add(createButton(ID_FINISH, "Finish", FINISH_ACTION_ID));
}
private Button createButton(final String id, final String label,
final String actionId) {
return new Button(id, Model.of(label)) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit() {
boolean isValid = ClaimWizardPanel.this.isValid(getForm());
if (!isValid) {
return;
}
executeNoArgAction(actionId);
}
};
}
private void addFeedbackGui() {
final FeedbackPanel feedback = addOrReplaceFeedback();
NakedObject adapter = getModel().getObject();
if (adapter == null) {
feedback.error("cannot locate object:"
+ getEntityModel().getNakedObjectMemento().toString());
}
}
private FeedbackPanel addOrReplaceFeedback() {
feedback = new ComponentFeedbackPanel(ID_FEEDBACK, this);
feedback.setOutputMarkupPlaceholderTag(true);
addOrReplace(feedback);
return feedback;
}
private void addValidator() {
add(new AbstractFormValidator() {
private static final long serialVersionUID = 1L;
@Override
public FormComponent<?>[] getDependentFormComponents() {
return new FormComponent<?>[0];
}
@Override
public void validate(Form<?> form) {
EntityModel entityModel = (EntityModel) getModel();
NakedObject adapter = entityModel.getObject();
ValidateObjectFacet facet = adapter.getSpecification()
.getFacet(ValidateObjectFacet.class);
if (facet == null) {
return;
}
String invalidReasonIfAny = facet.invalidReason(adapter);
if (invalidReasonIfAny != null) {
Session.get().getFeedbackMessages().add(
new FeedbackMessage(form, invalidReasonIfAny,
FeedbackMessage.ERROR));
}
}
});
}
}
}<html>
<body>
<wicket:panel>
<div class="claimWizard">
<form wicket:id="claimWizardPropertiesForm" class="inputForm">
<fieldset class="inputFormTable properties">
<div wicket:id="properties">
<div wicket:id="scalarNameAndValue">[scalar]</div>
</div>
<div class="feedbackPanel">
<span wicket:id="feedback"/>
</div>
<input class="submit" type="submit" wicket:id="previous"/>
<input class="submit" type="submit" wicket:id="next"/>
<input class="submit" type="submit" wicket:id="finish"/>
</fieldset>
</form>
</div>
</wicket:panel>
</body>
</html>