I found a lot of example how to create back button in wicket but it was in wicket 1.4 and lower where they use getPageMap . This feature isnt in wicket 1.5. I know there are some js feature as window.history.back() or history.go(-1) but I want implement some clear solution. Any idea ?
My idea was to store webPage in my own webSesion as Stack. Is this good ?
public class TournamentSession extends WebSession {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private static final long serialVersionUID = 1L;
private Stack<BasePage> previosPage = new Stack<BasePage>();
public TournamentSession(Request request) {
super(request);
}
public void addPreviosPage(BasePage basePage) {
logger.info(basePage.getClass().toString());
previosPage.push(basePage);
}
public BasePage getPreviousPage() {
BasePage basePage = previosPage.pop();
logger.info(basePage.getClass().toString());
return basePage;
}
}
and when page are render store actual page to this stack
Use session.getPageManager().getPage(id)
Related
I have a form that based on collected information generates a report. I have multiple sources from which to generate reports, but the form for them is the same. I tried to implement strategy pattern using an interface implementing report generator services, but that led to wicket complaining about serialization issues of various parts of the report generator. I would like to solve this without duplicating the code contained in the form, but I have not been able to find information on dynamic injection with #SpringBean.
Here is a rough mock up of what I have
public class ReportForm extends Panel {
private IReportGenerator reportGenerator;
public ReportForm(String id, IReportGenerator reportGenerator) {
super(id);
this.reportGenerator = reportGenerator;
final Form<Void> form = new Form<Void>("form");
this.add(form);
...
form.add(new AjaxButton("button1") {
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target)
{
byte[] report = reportGenerator.getReport(...);
...
}
});
}
}
If I do it this way, wicket tries to serialize the concrete instance of reportGenerator. If I annotate the reportGenerator property with #SpringBean I receive Concrete bean could not be received from the application context for class: IReportGenerator
Edit: I have reworked implementations of IRerportGenerator to be able to annotate them with #Component and now I when I use #SpringBean annotation I get More than one bean of type [IReportGenerator] found, you have to specify the name of the bean (#SpringBean(name="foo")) or (#Named("foo") if using #javax.inject classes) in order to resolve this conflict. Which is exactly what I don't want to do.
I think the behavior you're trying to achieve can be done with a slight workaround, by introducing a Spring bean that holds all IReportGenerator instances:
#Component
public class ReportGeneratorHolder {
private final List<IReportGenerator> reportGenerators;
#Autowired
public ReportGeneratorHolder(List<IReportGenerator> reportGenerators) {
this.reportGenerators = reportGenerators;
}
public Optional<IReportGenerator> getReportGenerator(Class<? extends IReportGenerator> reportGeneratorClass) {
return reportGenerators.stream()
.filter(reportGeneratorClass::isAssignableFrom)
.findAny();
}
}
You can then inject this class into your Wicket page, and pass the desired class as a constructor-parameter. Depending on your Spring configuration you might need to introduce an interface for this as well.
public class ReportForm extends Panel {
#SpringBean
private ReportGeneratorHolder reportGeneratorHolder;
public ReportForm(String id, Class<? extends IReportGenerator> reportGeneratorClass) {
super(id);
IReportGenerator reportGenerator = reportGeneratorHolder
.getReportGenerator(reportGeneratorClass)
.orElseThrow(IllegalStateException::new);
// Form logic omitted for brevity
}
}
As far as I am able to find, looking through documentation and even the source for wicket #SpringBean annotation, this isn't possible. The closest I got is with explicitly creating a proxy for a Spring bean based on class passed. As described in 13.2.4 Using proxies from the wicket-spring project chapter in Wicket in Action.
public class ReportForm extends Panel {
private IReportGenerator reportGenerator;
private Class<? extends IReportGenerator> classType;
private static ISpringContextLocator CTX_LOCATOR = new ISpringContextLocator() {
public ApplicationContext getSpringContext() {
return ((MyApplication)MyApplication.get()).getApplicationContext();
}
};
public ReportForm(String id, Class<? extends IReportGenerator> classType) {
super(id);
this.classType = classType;
final Form<Void> form = new Form<Void>("form");
this.add(form);
...
form.add(new AjaxButton("button1") {
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target)
{
byte[] report = getReportGenerator().getReport(...);
...
}
});
}
private <T> T createProxy(Class<T> classType) {
return (T) LazyInitProxyFactory.createProxy(classType, new
SpringBeanLocator(classType, CTX_LOCATOR));
}
private IReportGenerator getReportGenerator() {
if (reportGenerator = null) {
reportGenerator = createProxy(classType);
}
return reportGenerator;
}
}
I am adding a warning message using form.warn method but the warning message is not getting displayed. how do you add warning message on a wicket form
public class FormPanel extends BreadCrumbPanel {
public FormPanel(String id, IBreadCrumbModel breadCrumbModel)
{
super(id, breadCrumbModel);
Form<?> form = new Form<Void>("form");
form.add(new SaveButton("save"));
form.add(new FeedbackPanel("feedback"));
}
private class SaveButton extends Button {
private static final long serialVersionUID = 1L;
public SaveButton(String id) {
super(id);
}
#Override
public void onSubmit() {
validate(getForm());
}
}
validate(Form<?> form){
if(some logic)
form.warn(“message”);
}
}
You better move your validation logic to IValidator#validate() or IFormValidator#validate().
Currently you call it in Button#onSubmit(). That means Wicket believes everything is valid in your form fields and calls the last step - onSubmit(). Usually after onSubmit() you either render a completely different page or a new instance of the current page. In both cases the current page instance is lost together with its Form and its feedback messages.
If IValidator#validate() fails then Wicket will call onError() instead and re-render the current page instance.
In earlier wicket versions, making a checkbox required ensured that it has to be checked by the user, or else it would fail validation. This is no longer the case in wicket 6. Is there a standard way to achieve the same behavior now?
This is the relevant discussion on the topic:
http://apache-wicket.1842946.n4.nabble.com/quot-required-quot-for-Checkbox-td1854806.html
So you will have to use a validator on your checkbox:
public class TrueValidator implements IValidator<Boolean> {
private static final long serialVersionUID = 1L;
#Override
public void validate(IValidatable<Boolean> validatable) {
if (!Boolean.TRUE.equals(validatable.getValue())) {
validatable.error(new ValidationError(this));
}
}
}
I have a bean named SignUpBean and it's editor is SignUpBeanEditor and following is its Driver interface.
public interface SignUpDriver extends SimpleBeanEditorDriver<SignUpBean, SignUpEditor>{
}
Following is entry point class
public class Signup implements EntryPoint {
private SignUpDriver signUpDriver;
private SignUpEditor signUpEditor;
private SignUpBean signUpBean;
private VerticalPanel verticalPanel;
private Label signUpLbl;
private Button submitButton;
private Button cancelButton;
private RequestBuilder requestBuilder;
final SignUpConverter signUpConverter=GWT.create(SignUpConverter.class);
public void onModuleLoad() {
signUpLbl = new Label("Sign Up");
signUpDriver = GWT.create(SignUpDriver.class);
signUpBean = new SignUpBean();
signUpEditor = new SignUpEditor();
submitButton = new Button("Submit");
cancelButton = new Button("Cancel");
signUpDriver.initialize(signUpEditor);
signUpDriver.edit(signUpBean);
System.out.println(signUpBean.getUserName());
submitButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
SignUpBean signUpBeanEdited=signUpDriver.flush();
}
}
}
}
I am getting only null value from signUpBeanEdited after giving value in UI. If i am initializing SignUpBean with constructor then also data is not binding to UI. My problem is I cant bind data in GWT UI using editor framework.
The fields( sub editors ) declared in SignUpEditor should be of at least DEFAULT scope. I guess you declared them as private. If so, the Editor Impl classes generated cannot access the fields to bind the data.
Changing scope to at least DEFAULT might solve your problem.
Stemming from this article more efficient way of updating UI from service I was wondering if I could take that a step further and implement the following. I may have a misunderstanding of my Apps lifecycle though.
public class MyApplication extends Application {
private static final String TAG = MyApplication.class.getSimpleName();
private static Stack<MyActivity> mActivityStack = new Stack<MyActivity>();
private static String mTopActivity = "none";
public static void pushActivity(MyActivity activity)
{
mActivityStack.push(activity);
mTopActivity = activity.getClass().getSimpleName();
Log.i(TAG, "push::"+mTopActivity);
}
public static void popActivity()
{
Log.i(TAG, "pop::"+mTopActivity);
mActivityStack.pop();
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.w(TAG, "low memory!!!");
Log.w(TAG, "Current::"+mTopActivity);
}
}
public class MyActivity extends Activity
{
private static final String TAG = MyActivity.class.getSimpleName();
public void onCreate(Bundle last)
{
super.onCreate(last);
MyApplication.pushActivity(this);
}
public void onDestroy()
{
super.onDestroy();
MyApplication.popActivity();
}
}
Would the stack be valid during the lifecycle of the application?
As CommonsWare said, this did not work out. Also, it is not a great idea to derive from Activity, because you would then have to also derive listactivity, preferenceactivity, etc. Obviously, I did not think this would solve any problem it was just an experiment in android life cycles.
Would the stack be valid during the lifecycle of the application?
Of course it won't be valid. You assume every activity is created and destroyed in the same sequence. They won't be in many cases (e.g., user presses HOME).
Whatever problem you think you are solving this way, this is not the right solution by any stretch of the imagination.