Wicket and Reusable Link - hyperlink

'm trying to create a reusable link class that extends Link. I have a webpage with about 7 menu items and I'm using inheritance for my application. I want to create a reusable link class to shorten the length of my code..
As of now the link creates and runs fine when I add(new Link....) as an anonymous class inside oninitialize().
The custom link class (which is an inner class of the base page) works fine when I hard code the instance of the new page to go to, and assign it to a "Page" reference, then pass it into setResponsePage();
The problem is, I'm passing trying to be able to pass object through the constructor generically. When I pass it through the constructor, and try to travel to the new page, I get a session has expired.
I've tried using generics for the class, and I've also tried just declaring a Page reference as a parameter value. Am I supposed to use some sort of Model? Or can someone provide an example of how to do this? I want to be able to use this custom link class to add new links for the 7 menu items, which each have there own class...
Code that works:
add(new Link("userPageLink")
{
public void onClick()
{
pageTitle = "User";
Page next = new UserPage();
setResponsePage(next);
}
});
Modified code that gives page expired upon click:
public class CustomLinkToNewPage extends Link
{
private String title;
private Page next;
public CustomLinkToNewPage(String id, String title, Page newPage)
{
super(id);
next = newPage;
this.title = title;
}
#Override
public void onClick()
{
SSAPage.pageTitle = title;
setResponsePage(next);
}
}

This might be due to the fact that in the first version you crate the Page object when the onClick method of the Link object is called and in the second version, the Page object is created on Page-construction (way earlier).
You might get the result if you pass the Pageclass of the responsepage instead on an instance.
Component features setters for these either with
public final <C extends IRequestablePage> void setResponsePage(java.lang.Class<C> cls, PageParameters parameters)
or without parameters.
public final <C extends IRequestablePage> void setResponsePage(java.lang.Class<C> cls)
See Javadoc for more information.

I ended up doing:
public class CustomLinkToNewPage<T extends SSAPage> extends Link
SSAPage is my base page that extends WebPage... So any object passed in to this class's constructor must extend SSAPage as well.
public CustomLinkToNewPage(String id, Class<T> name)
Then I passed in the .class reference to the object, and created a new instance of the object using reflection.. then set that instance to Page, and passed it to setResponsePage in my onClick. Worked nicely, as I couldn't figure out how to do Nicktar's way. So this an alternative in case anyone else runs into this issue.

Related

Slim framework - Why does not halt method work if the controller extend the Slim class?

I have seen a very interesting thing. I did a little mvc/rest framework based on the Slim framework.
$app->put('/:id', function ($id) {
$app->halt(500, "Error") // Here this is working.
(new RestController)->editItem($id);
})->via('put');
So I wrote a RestController which extends the BaseController, and my BaseController extends the Slim framework.
class BaseController extends \Slim\Slim {
/**
* #var \app\models\AbstractModel
*/
protected $model;
public function __construct() {
$settings = require(__DIR__ .'/../configurations/slim.php');
parent::__construct($settings);
}
}
So my BaseController can uses the Slim class's methods and properties.
class RestController extends BaseController {
public function editItem($id) {
$data = $this->getRequestBody();
$result = $this->model->update($id, $data['data']);
// This is absolutely not working, but it seems my application will die in this case.
// Because I cannot see any written message (with echo or print methods...)
// This will always return with a 200 staus code and blank page!
$this->halt(404, json_encode(array('status' => "ERROR")));
}
}
But this will work fine... and I do not get it, why?
class RestController extends BaseController {
public function editItem($id) {
$data = $this->getRequestBody();
$result = $this->model->update($id, $data['data']);
// This will work.
$app = Slim::getInstance();
$app->halt(204, json_encode(array('status' => "ERROR")));
}
}
Anyone has a good ide?
You construct a new RestController in your route by doing (new RestController). Although it extends Slim/Slim in the class hierarchy, it is a new instance of it; it is not a copy of or reference to $app, the Slim application that is actually being run.
This causes issues in the first case: you say $this->halt(...) while $this is the newly constructed RestController which is a new instance of a Slim app, not the one that is currently running. Therefore the halt call has no effect on your the output of your application.
In the second case, you say $app->halt(...) where $app is Slim::getInstance(), the global instance of your Slim application, which is the actual running Slim app. Therefore the halt call has effect on the output of your application.
You can solve the issue either by using the second approach, or by instantiating your global $app variable as a RestController, and then you can do:
$app->put('/:id', function ($id) use ($app) {
$app->halt(500, "Error") // Here this is working.
$app->editItem($id);
})->via('put');
NB; you forgot to put use ($app) in the code posted to your question, I added it in my code above. Is it present in the code you are actually running? Otherwise the $app->halt() call should result in an error in any case.

How to internationalize a converter or renderer in Wicket?

I'm translating a web application and things are generally going smoothly with wicket:message and properties files. But Wicket always wants to have a component for looking up strings.
How can I translate converters and renderers (i.e. implementations of IConverter and IChoiceRenderer) which don't have access to any Wicket component in their methods?
So far I found one way - Application.get().getResourceSettings().getLocalizer().getString(key, null) - but I have to make the strings "global", i.e. associated with the application class. That's not nice for separation and reuse. How can I do it better?
I think you should invent you own way how to achieve this. Here in my current project we registered our own IStringResourceLoader like this:
IStringResourceLoader stringResourceLoader = new OurOwnResourceLoaderImpl();
Application.get().getResourceSettings().getStringResourceLoaders().add(stringResourceLoader);
Then for example in IChoiceRenderer we just call Application.get().getLocalizer().getString("key", null).
Inside our IStringResourceLoader we are looking for bundles (property files) with some string pattern according our own conventions.
Or you can just register localization bundle (ie. properties file) distributed inside your library's jar in Application#init through org.apache.wicket.resource.loader.BundleStringResourceLoader.
Afaik there is no standard way to do that so it's up to you what path you choose.
Updated:
I found another solution how your library/extension can register it's own localization by itself so you needn't to touch Application#init or create your own IStringResourceLoaders.
There is preregistered string resource loader org.apache.wicket.resource.loader.InitializerStringResourceLoader (see wickets default IResourceSetting implementation ie. ResourceSetting and it's constructor) which uses wicket's Initializer mechanism - see IInitializer javadoc - basically you add wicket.properties file in your jar class root (ie. it is in default/none package) and inside file there is:
initializer=i.am.robot.MyInitilizer
then i.am.robot.MyInitilizer:
public class MyInitializer implements IInitializer {
/**
* #param application
* The application loading the component
*/
void init(Application application) {
// do whatever want
}
/**
* #param application
* The application loading the component
*/
void destroy(Application application) {
}
}
and now you create your localization bundles in same package and same name as IInitializer implementation (in our example MyInitializer)
I think I found another way...
I noticed that IStringResourceLoader also has a method String loadStringResource(Class<?> clazz, String key, Locale locale, String style); (and one more parameter for variation in newer Wicket versions) which does not require a component. clazz is supposed to be a component class, but... it doesn't actually have to be :)
I was able to implement my own class MyLocalizer extends Localizer with a new method
getString(String key, Class<?> cl, IModel<?> model, Locale locale, String defaultValue)
which works in a similar way to
getString(String key, Component component, IModel<?> model, String defaultValue)
but uses the class directly instead of a component. It still uses the same properties cache and resource loaders.
Then I wrote an abstract class MyConverter implements IConverter which has a MyLocalizer getLocalizer() and a few getString methods like the Component class. Basically it does getLocalizer().getString(key, getClass(), model, locale, defaultValue), so the properties can now be attached to the converter class.
Seems to work :)
If I understand your question...
You can use package based properties that means if you put your keys/values into a property file 'package.properties' in a package. Each localized resource of any subpackage under that package returns the value associated to the requested key until you override it in another property file.
The file name is 'package.properties' in Wicket prior to 1.6.x and 'wicket-package.properties' in Wicket 1.6+
See
https://cwiki.apache.org/confluence/display/WICKET/Migration+to+Wicket+6.0#MigrationtoWicket6.0-package.propertiesrenamedtowicket-package.properties
However it works just for componet, outside the componet (when component argument is null), it is possible to use:
WicketApplication.properties (the WebApplication class is WicketApplication.class, this property file is in the same package).
applicationGlobalProperty=My Global Localized Property
wicket-package.properties (package based, place it in the same package as the page)
localText=Localized text: A local component text based on wicket-package.properties
LocalizedPage.html (markup template)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Localized Page</title>
</head>
<body xmlns:wicket="http://wicket.apache.org">
<div>
<div>
<h2>Texts</h2>
<div>
<wicket:message key="localText"/> <br/>
<span wicket:id="localizedLabel"></span>
</div>
</div>
</div>
</body>
</html>
LocalizePage.java (code)
public class LocalizedPage extends WebPage {
private static final long serialVersionUID = 1L;
public LocalizedPage() {
super();
}
#Override
protected void onInitialize() {
super.onInitialize();
add(new Label("localizedLabel", new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
#Override
public String getObject() {
return WicketApplication.get().getResourceSettings().getLocalizer().getString("applicationGlobalProperty", null);
}
}));
}
}
See the full example on https://repo.twinstone.org/projects/WISTF/repos/wicket-examples-6.x/browse

Adding Dagger to an existing project

I'm trying to add Dagger to an existing web application and am running into a design problem.
Currently our Handlers are created in a dispatcher with something like
registerHandler('/login', new LoginHandler(), HttpMethod.POST)
Inside the login handler we might call a function like
Services.loginService.login('username', 'password');
I want to be able to inject the loginService into the handler, but am having trouble figuring out the best approach. There is a really long list of handlers in the dispatcher, and injecting them all as instance variables seems like a large addition of code.
Is there a solution to this type of problem?
Based on your comment about having different services to inject. I would propose next solution.
ServicesProvider:
#Module(injects = {LoginHandler.class, LogoutHandler.class})
public class ServicesProvider {
#Provides #Singleton public LoginService getLoginService() {
return new LoginService();
}
}
LoginHandler.java:
public class LoginHandler extends Handler {
#Inject LoginService loginService;
}
HttpNetwork.java
public class HttpNetwork extends Network {
private ObjectGraph objectGraph = ObjectGraph.create(new ServicesProvider());
public registerHandler(String path, Handler handler, String methodType) {
getObjectGraph().inject(handler);
}
}
There is one week point in this solution - you can't easily change ServiceProvider for test purpose (or any other kind of purpose). But if you inject it also (for example with another object graph or just through constructor) you can fix this situation.

Delete Persistent Store data when App is uninstalled/deleted

I have a BlackBerry application that starts (App load) with a Registration screen when the App is first installed. Later, the App will load with the home screen. Registration screen only appears on first load. I am achieving this by storing a boolean value in PersistentStore. If the value exists, then Registration screen will not appear.
PersistentStoreHelper.persistentHashtable.put("flagged",Boolean.TRUE);
PersistentStoreHelper.persistentObject.commit();
UiApplication.getUiApplication().pushScreen(new MyScreen());
I am aware of the fact that in order to delete the Persistent Store on deleting/uninstalling the App, I have to make the Hashtable a subclass of my own and therefore I have declared the Hashtable in a separate class:
public class PersistentStoreHelper extends Hashtable implements Persistable{
public static PersistentObject persistentObject;
public static final long KEY = 0x9df9f961bc6d6daL;
public static Hashtable persistentHashtable;
}
However this has not helped and the boolean value of flag is not cleared from PersistentStore. Please advice.
EDIT: When I change the above PersistentStoreHelper class to
public static PersistentObject persistentObject =
PersistentStore.getPersistentObject(KEY);
and remove
PersistentStoreHelper.persistentObject =
PersistentStore.getPersistentObject(PersistentStoreHelper.KEY);
from class B where boolean value is being saved, I observe that the boolean value is removed every time the App is closed. This should not happen and the value should only be removed in case the App is deleted/uninstalled. Any pointers?
The way this works is that the BlackBerry OS looks at the objects you are storing in the PersistentStore. If it recognizes that those objects can only be used by your app, then it will delete them when you uninstall the app. However, if the classes of the stored objects are classes that are used by other apps, then your data will not be deleted.
You have declared your helper class like this:
public class PersistentStoreHelper extends Hashtable implements Persistable{
but the helper class is not what is being stored. Your helper class is just a helper, that stores other things for you. In your case, it is storing this:
public static Hashtable persistentHashtable;
but, that object is of type java.util.Hashtable, which is a class used by many apps. So, it won't be deleted when you uninstall your app. What you should do is something like this:
public class PersistentStoreHelper implements Persistable { // so inner class = Persistable
public static PersistentObject persistentObject;
public static final long KEY = 0x9df9f961bc6d6daL;
/**
* persistentHashtable is now an instance of a class that
* only exists in your app
*/
public static MyAppsHashtable persistentHashtable;
private class MyAppsHashtable extends Hashtable implements Persistable {
// don't need anything else ... the declaration does it all!
}
}
I can't see it here, but I'm assuming that somewhere you have this code:
persistentObject = PersistentStore.getPersistentObject(KEY);
and then when you want to save the data back to the store, you're doing something like this;
persistentHashtable.put("SomeKey", someNewData);
persistentObject.setContents(persistentHashtable);
persistentObject.commit();
just adding data to the persistentHashtable doesn't save it (permanently). Hopefully, you already had that part somewhere.
Note: if you make these changes, don't expect this line of code to work, the next time you run your app:
persistentHashtable = (MyAppsHashtable)persistentObject.getContents();
because the last version of your code did not use the MyAppsHashtable class, so the loaded data won't be of that type. This is one reason that it's important to get this right the first time. In general, I always wind up saving data in the PersistentStore that's contained in one top level Hashtable subclass, that implements Persistable. I may later change what goes in it, but I won't ever change the signature of that top-level storage object. Hopefully, you haven't released your app already.
Update: In response to your comment/question below:
if (PersistentStoreHelper.persistentObject.getContents() == null) {
PersistentStoreHelper.persistentHashtable = new MyAppsHashtable();
PersistentStoreHelper.persistentObject.setContents(PersistentStoreHelper.persist‌entHashtable);
} else {
PersistentStoreHelper.persistentHashtable =
(MyAppsHashtable)PersistentStoreHelper.persistentObject.getContents();
}

How to set Session-Parameter after JSF Navigation-Rule in a portlet environment with the to-view-id

We are currently facing one problem in our portlet-environment using JSF2.
The application is creating dynamic portal-pages for the actual user session...think of it as Eclipse editor-views where the user can edit entities. So for now I call the dynamic-views editors :-)
The problem we are facing now, is following. The user navigates to a editor and works on the portlet(s). The displayed views in each portlet change over time of course. Now he wants to have a look on another entity which is displayed in another editor. But when he navigates back to the first editor, the state of portlets changes back to the default views.
In the portlet-world each portlet each portlet gets the view it should display via a parameter which is stored in the PortletSession and I can easily change that parameter as well. I know that this parameter is causing the trouble because when the changes the editors, the portlets will always check this parameter to decide which view to show.
request.getPortletSession().setAttribute("com.ibm.faces.portlet.page.view", "/MyPage.xhtml");
My idea was, to somehow add a callback to each JSF-navigation which will set this parameter to the view the navigation is going to display (possibly including view-params).
Is it possible to have a standard callback? If not, would be possible to execute some kind of EL in the navigation-rule that will set this parameter?
somehow add a callback to each JSF-navigation
You could perform the job in a custom ConfigurableNavigationHandler. Here's a kickoff example:
public class MyNavigationHandler extends ConfigurableNavigationHandler {
private NavigationHandler parent;
public MyNavigationHandler(NavigationHandler parent) {
this.parent = parent;
}
#Override
public void handleNavigation(FacesContext context, String from, String outcome) {
// TODO: Do your job here.
// Keep the following line untouched. This will perform the actual navigation.
parent.handleNavigation(context, from, outcome);
}
#Override
public NavigationCase getNavigationCase(FacesContext context, String fromAction, String outcome) {
return (parent instanceof ConfigurableNavigationHandler)
? ((ConfigurableNavigationHandler) parent).getNavigationCase(context, fromAction, outcome)
: null;
}
#Override
public Map<String, Set<NavigationCase>> getNavigationCases() {
return (parent instanceof ConfigurableNavigationHandler)
? ((ConfigurableNavigationHandler) parent).getNavigationCases()
: null;
}
}
To get it to run, register it as follows in faces-config.xml:
<application>
<navigation-handler>com.example.MyNavigationHandler</navigation-handler>
</application>

Resources