I'm a fairly experienced Wicket user but I'm making my first foray into 1.5 and the mountPage() syntax is defeating me.
I'm clearly doing something wrong because I can't fine a single reference of someone having this same issue. So here it goes:
This is what I have in my init() method:
#Override
public void init()
{
super.init();
System.out.println("mounting: /requirement/${id}");
mountPage("/requirement/${id}", RequirementPage.class);
}
I've verified this is working by changing the "requirement" part to other things and back. This is the (only) constructor for RequirementPage:
public RequirementPage()
{
try
{
PageParameters params = getPageParameters();
System.out.println("named keys: " + params.getNamedKeys());
System.out.println("index keys: " + params.getIndexedCount());
StringValue value = params.get("id");
System.out.println("requirement: " + value);
In my server console (Jetty8) I see this on startup:
mounting: /requirement/${id}
And when I make a request to /requirement/0 I see this:
named keys: []
index keys: 0
requirement: null
I've looked at a number of things and I can't see anything different about what I am doing from what the wiki, or other examples show.
Any help is appreciated.
thanks,
-James
You need to provide Wicket a constructor with PageParameters, otherwise there's no possibility for wicket to wrap those parameters and provide it to your page.
Apart from that, you can access requestparameters via getRequestCycle().getRequest().getRequestParameters() without having a constructor with pageparameters, but as far as youd like wicket to manage and mount your pages and parameters and having them bookmarkable, it is necessary to provide a default constructor, with or without pageparameters, occording to your requirement of recieving parameters or not.
You can try this;
#Override
public void init()
{
super.init();
mountPage("requirement", RequirementPage.class);
}
Then call the url like this "http://localhost:8080/requrement?id=111" And then you can get id with your constructor. But you can use your web page constructor like this;
public RequirementPage(PageParameters parameters)
{
...
}
Related
I am trying to understand how the RESTful Server in Hapi Fhir works and I wanted to implement some #Search methods for Observation resources.
Currently, I have this #Read operation, which successfully works when trying to access the resource (like this: http://localhost:8080/NewFHIRServer/fhir) from the browser:
#Read()
public Observation readObservationById(#IdParam IdDt theId) {
for (Entry<Long, Deque<Observation>> entry : myPatientIdToObservations.entrySet())
{
for (Observation obs : entry.getValue()) {
if (obs.getId().equals(theId)) {
return obs;
}
}
}
throw new ResourceNotFoundException(theId);
}
However, when I try to do something similar for the #Search operation, I am getting errors. I would like to be able to get the response by running the search like this (or similar):
Bundle response = client
.search()
.forResource(Observation.class)
.where(Observation.SUBJECT.hasId("Patient/1"))
.execute();
What parameters do I need to have in my #Read method in order to make this possible? The error I am getting right now is the following:
The FHIR endpoint on this server does not know how to handle GET
operation[Observation] with parameters [[subject]]
and it is obvious why it doesn't work, because my header looks like this:
public Observation searchObservationById(#IdParam IdDt theId)
I have been looking at examples to try to figure this out and I don't quite understand what the syntax in this parameter means:
public List<Patient> getPatient(#RequiredParam(name = Patient.SP_FAMILY) StringParam theFamilyName)...
How would you make the query in order to use this last example?
Thank you
To implement a search method, you need to use #Search instead of #Read on the method. You then use zero-or-more parameters annotated with #OptionalParam or #RequiredParam.
To make your specific example work, you need a search method which implements the _id search parameter, e.g.
#Search
public List<Patient> getPatient(#RequiredParam(name = Patient.SP_RES_ID) StringParam theId) {
}
I've got in my .tml file something like this:
<t:beaneditform t:id="adForm" object="editableAd"
reorder="actiontype,shops,movies,streams,widgets" ....
My question is how to access (refer) actionType, which is an Enum (and in fact SELECT) in .java file? I just need to handle event when user changes the value of this select (dropdown), obviously before submitting the form itself.
If something like this would work for me...
#OnEvent(component = "adForm.actionType", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(String value) {
log.info("value is: " + value);
}
To be updated with the changed value in a Select html component on the client side, have a tapestry select component in your template file with a t:zone attribute (i.e. in your case it could point to any dummy zone, this is only needed to be set correctly if you need to update a zone when a value is changed)
Also set the t:value attribute to your enum variable in your page\component java file, usually this variable will be annotated with tapestry's #Property.
Example:
<t:select t:id="myEnumVariable" t:zone="dummyZone" t:value="myEnumVariable"/>
myEnumVariable is used to refer to your class's variable AND to act as an ID (i.e. the actual string myEnumVariable is used as an id), this is not necessary, but it's more readable and maintainable that way)
public class MyClass{
#Property
private MyEnum myEnumVariable;
#OnEvent(component = "myEnumVariable", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(**MyEnum** newValue) {
this.myEnumVariable = newValue; // <<<<<<
log.info("value is: " + myEnumVariable );
}
}
If you don't mind using the ChenilleKit framework for tapestry you could try using the
framework's OnEvent mixin.
You 'll find the example on the link I share but basically you add two attributes the select tag:
<t:select t:id="myselect" ... t:mixins="ck/OnEvent" t:event="change" />
then you add the event handler on your java class:
#OnEvent(component="myselect", value='change')
public void onChangeDoSomething(String value) {
hope that helps, by the way I think Muhammad's answer is equally correct (and doesn't requires the use of an extra framework).
Log4j default initialization goes through a procedure to find and use a URL to configure with. Afterward, how can you find out what URL was ultimately used, without having to code the same procedure yourself? (If you have to code it yourself, you might not get it exactly the same as log4j does, and also it might change in a future release.)
If you are willing to use AspectJ LTW (load-time weaving), you can take a look at the static initialisation of LogManager mentioned by Ian Roberts. In log4j 1.2.14 it looks like this:
static {
// (...)
// if there is no default init override, then get the resource
// specified by the user or the default config file.
if (override == null || "false".equalsIgnoreCase(override)) {
// (...)
URL url = null;
// (...)
// If we have a non-null url, then delegate the rest of the
// configuration to the OptionConverter.selectAndConfigure method.
if (url != null) {
LogLog.debug("Using URL [" + url + "] for automatic log4j configuration.");
OptionConverter.selectAndConfigure(
url, configuratorClassName, LogManager.getLoggerRepository()
);
} else {
LogLog.debug("Could not find resource: [" + configurationOptionStr + "].");
}
}
}
Obviously if a default URL could be determined then OptionConverter.selectAndConfigure(URL, ..) will be called at one point within the static block in order to initialise log4j with that URL.
By means of AspectJ it is pretty simple to catch that method invocation:
import java.net.URL;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.LogManager;
public aspect Log4jAspect {
before(URL defaultURL) :
within(LogManager) &&
cflow(staticinitialization(LogManager)) &&
call(* OptionConverter.selectAndConfigure(URL, ..)) &&
args(defaultURL, ..)
{
System.out.println("log4j default URL = " + defaultURL);
}
}
In prose this code means:
If we are within class LogManager and
within the control flow of the static class initialisation and
OptionConverter.selectAndConfigureis called,
then capture the first argument (the URL) and
print it to the console (you could just as well do something else).
If there is no default URL, nothing will be printed. Instead of printing the URL you could assign it to a static member of any class or whatever you like.
This is a solution for your problem, I tested it and it works. I would be happy to receive the bounty for answering your question, even though maybe the solution uses a technology you did not have in mind. But it solves the problem. :-)
Edit: It is also possible to explicitly intercept the log call in the case that no default URL is found, even though I do not think it is necessary. I just wanted to mention it.
The procedure used is hard-coded in a static initializer block in LogManager, so there doesn't appear to be a way to hook into it. The only place where it tells you what's going on is
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
but LogLog itself is hard-coded to use System.out.println for these messages so the only possibility I can see is to switch on debugging (-Dlog4j.debug=true) and somehow hook in to System.setOut before log4j is initialized, then parse the debug log message. But that is probably even more fragile than coding the config procedure yourself.
Even then, there may have been other programmatic configuration applied after the default configuration procedure (e.g. a Spring Log4jConfigListener) - there isn't necessarily a single configuration URL as such.
It might be worth putting in a log4j feature request to factor out the config file search code into a static method that you can call from elsewhere, but that wouldn't help when you might have to cope with earlier versions of log4j.
If you can setup your own Configurator you can do something like that:
Setup the JAVA system property : -Dlog4j.configuratorClass=MyConfigurator
And then have your configurator instance intercepts the doConfigure call.
public class MyConfigurator implements Configurator
{
public static URL url;
#Override
public void doConfigure(URL url, LoggerRepository repository)
{
this.url = url;
new PropertyConfigurator().doConfigure(url, repository);
}
}
Insert this into your java call:
-Dlog4j.configDebug=true
Thats all.
Does Wicket somehow allow passing both of the following kinds of params in a PageParameters object? Apparently not?
accountId which is shown in the URL (/account/<ID>)
infoMessage parameter which is not shown in the (bookmarkable) URL
I'm currently using IndexedHybridUrlCodingStrategy for the page in question, and simply trying parameters "0" and "infoMessage" gives this exception:
WicketMessage: Not all parameters were encoded. Make sure all
parameter names are integers in consecutive order starting with zero.
Current parameter names are: [0, infoMessage]
If I change "infoMessage" parameter name into "1", it works, but yields an ugly URL (in this case something like /account/42/Tosite%20108207%20tallennettiin.5) which is not what I want.
Now, the obvious answer perhaps is that infoMessage shouldn't be in PageParameters. But thing is, I tried adding it as normal constructor parameter instead, like so:
public AccountPage(PageParameters parameters, String infoMessage) {
// ...
}
But this approach fails in one important use case. After deleting a persistent "Record" object related to the Account, the following does not load the AccountPage properly (the deleted record is still visible). This code is executed in onClick() of an AjaxFallbackLink.
setResponsePage(new AccountPage(AccountPage.pageParameters(account), message));
On the other hand, my original approach...
setResponsePage(AccountPage.class, AccountPage.pageParameters(account));
... works fine, as it somehow loads the AccountPage "more thoroughly", but, again, I don't know how to pass the infoMessage parameter cleanly.
(AccountPage.pageParameters() above is a simple static utility for creating appropriate PageParameters with "0" = account id. The AccountPage constructor always loads the account from persistence using the ID.)
Any ideas? Perhaps using AjaxFallbackLink partially causes the problem?
Using Wicket 1.4.
From what I see in your question, you try to render both a bookmarkable page and show a feedback message to the user (most probably in a FeedbackPanel), but you don't want that message to be part of the URL.
What you want to do is tell the Session that you have an informational message, and let the feedback panel handle the message.
#Override void onSubmit() {
... save object ...
getSession().info("Object ... has been saved");
setResponsePage(ObjectPage.class, new PageParameters("id="+object.getId()));
}
In this case you tell Wicket to temporarily store a message in the session, until it gets rendered by a feedback panel. This idiom is also known as "flash messages".
You can't use both PageParameters and another parameter as constructor arguments, because Wicket can't create your page instance with such a constructor when the page is requested. Wicket only knows how to instantiate pages with default constructors or pages with a PageParameters parameter.
HI guys,
I wanted to add an AJAX Event to my Homepage, but it doesn't work! I figured out, that if I delete the onComponentTag function it works well. I have no clue why this happend, maybe you can help me!
Thats my Code:
final TextField<String> searchInput = new TextField<String>("searchInput", model) {
#Override
protected void onComponentTag(final ComponentTag tag) {
super.onComponentTag(tag);
tag.put("id", this.getId());
if (params.getString("search") != null) {
tag.put("value", params.getString("search"));
}
}
};
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.addComponent(searchInput);
}
});
Thx a lot for helping me!
CU
Firstly, you don't need to be overriding onComponentTag() at all. As seanizer states, if your really need to specify a markup ID yourself, use setMarkupId(id). You should understand why it is recommended that Wicket manages component IDs.
Secondly, the value attribute that you are adding is unnecessary - Wicket adds this automatically for this component. The value assigned is the value of the component's model object. See the source for TextField.onComponentTag().
Thirdly, again as seanizer states, components that are to be updated by ajax need to output their markup IDs - Wicket's ajax implementation uses the ID as the selector for the element. Additionally, all Wicket ajax behaviours that extend AbstractDefaultAjaxBehavior automatically set outputMarkupId(true) on the component they are bound to (see the source for AbstractDefaultAjaxBehavior.onBind()). This includes AjaxFormComponentUpdatingBehavior.
So:
String id = "searchInput";
final TextField<String> searchInput = new TextField<String>(id, model);
searchInput.setMarkupId(id);
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.setOutputMarkupId(true);
target.addComponent(searchInput);
}
});
Finally, I'd question what you're actually trying to achieve with this behaviour. I don't see any reason to round-trip this event to the server. Surely some client-side JS is more appropriate?
tag.put("id", this.getId());
is not the way to do it in wicket.
instead, use
component.setOutputMarkupId(true)
(either in your component constructor or in your behavior's bind() method) to make wicket write the id, and if you absolutely need to control what the id is (which is almost never the case) you can do
component.setMarkupId("myId")
also, you probably shouldn't assign the tag value yourself, use a model (model handling is extremely smart in wicket, read more about models). There are valid uses for onComponentTag, but they are way beyond what you are doing. Let wicket do what wicket does best and everything will be fine.
EDIT:
OK, some more clarification
have a look at the source code of AjaxFormComponentUpdatingBehavior, especially the part where the javascript event handler is generated.
protected final CharSequence getEventHandler()
{
return generateCallbackScript(
new AppendingStringBuffer("wicketAjaxPost('")
.append(getCallbackUrl(false)).append(
"', wicketSerialize(Wicket.$('"
+ getComponent().getMarkupId() + "'))"));
}
as you can see, wicket uses getMarkupId() to determine the actual id. The id you set using tag.put(id) is totally unknown to wicket and hence the behavior cannot work.
The standard thing to do is setOutputMarkupId(true). This is the only proper way to tell wicket to render the id (other than setOutputMarkupPlaceholder(true), which internally calls the former method). That way you make sure that the id wicket writes is the id wicket knows about. If this doesn't render the id, you are probably breaking some default behavior by overwriting onComponentTag.
Have a look at the source code of Component, especially at onComponentTag(), the method you are overriding:
protected void onComponentTag(final ComponentTag tag) {
// if(setOutputMarkupId(true) was set)
if (getFlag(FLAG_OUTPUT_MARKUP_ID)) {
// set id attribute
tag.put(MARKUP_ID_ATTR_NAME, getMarkupId());
}
}
[The comments are mine. BTW, this is the source of an ancient version, but I didn't find any current source online, and the functionality hasn't changed.]
Now if, as in your case, you want to set the component id manually, you must use
component.setMarkupId("myId")
and of course
setOutputMarkupId(true)
as well. If that doesn't work, go to the wicket JIRA site and file a bug. But I doubt it, this is standard functionality that works for thousands of users.