Skip executing <ui:include> when parent UI component is not rendered - jsf-2

I have the following construct at several places in my webapp in order to conditionally render page fragments depending on some actions:
<h:panelGroup rendered="#{managedBean.serviceSelected == 'insurance'}">
<ui:include src="/pages/edocket/include/service1.xhtml" />
</h:panelGroup>
I have observed, that the <ui:include> is still executed even when the rendered attribute evaluates false. This unnecessarily creates all backing beans associated with the service1.xhtml file which is been included.
How can I skip executing the <ui:include> when the parent UI component is not rendered, so that all those backing beans are not unnecessarily created?

Unfortunately, this is by design. The <ui:include> runs as being a taghandler during the view build time, while the rendered attribute is evaluated during the view render time. This can be better understood by carefully reading this answer and substituting "JSTL" with "<ui:include>": JSTL in JSF2 Facelets... makes sense?
There are several ways to solve this, depending on the concrete functional requirement:
Use a view build time tag like <c:if> instead of <h:panelGroup>. This however puts implications into the #{managedBean}. It can't be view scoped and should do its job based on HTTP request parameters. Exactly those HTTP request parameters should also be retained in subsequent request (by e.g. <f:param>, includeViewParams, etc) so that it doesn't break when the view is restored.
Replace <ui:include> by a custom UIComponent which invokes FaceletContext#includeFacelet() during the UIComponent#encodechildren() method. So far no such component exist in any of the existing libraries. But I can tell that I've already such one in mind as a future addition for OmniFaces and it works as intuitively expected here at my test environment (with Mojarra). Here's a kickoff example:
#FacesComponent(Include.COMPONENT_TYPE)
public class Include extends UIComponentBase {
public static final String COMPONENT_TYPE = "com.example.Include";
public static final String COMPONENT_FAMILY = "com.example.Output";
private enum PropertyKeys {
src;
}
#Override
public String getFamily() {
return COMPONENT_FAMILY;
}
#Override
public boolean getRendersChildren() {
return true;
}
#Override
public void encodeChildren(FacesContext context) throws IOException {
getChildren().clear();
FaceletContext faceletContext = ((FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY));
faceletContext.includeFacelet(this, getSrc());
super.encodeChildren(context);
}
public String getSrc() {
return (String) getStateHelper().eval(PropertyKeys.src);
}
public void setSrc(String src) {
getStateHelper().put(PropertyKeys.src, src);
}
}

Use conditional expression as ui:include src:
<h:panelGroup>
<ui:include
src="#{managedBean.serviceSelected == 'insurance' ?
'/pages/edocket/include/service1.xhtml'
:
'/pages/empty.xhtml'}"
/>
</h:panelGroup>

Related

JSF SelectOneMenu value cannot be user defined type? [duplicate]

I am creating a web application, where you have to read a list of objects / entities from a DB and populate it in a JSF <h:selectOneMenu>. I am unable to code this. Can someone show me how to do it?
I know how to get a List<User> from the DB. What I need to know is, how to populate this list in a <h:selectOneMenu>.
<h:selectOneMenu value="#{bean.name}">
...?
</h:selectOneMenu>
Based on your question history, you're using JSF 2.x. So, here's a JSF 2.x targeted answer. In JSF 1.x you would be forced to wrap item values/labels in ugly SelectItem instances. This is fortunately not needed anymore in JSF 2.x.
Basic example
To answer your question directly, just use <f:selectItems> whose value points to a List<T> property which you preserve from the DB during bean's (post)construction. Here's a basic kickoff example assuming that T actually represents a String.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{bean.names}" />
</h:selectOneMenu>
with
#ManagedBean
#RequestScoped
public class Bean {
private String name;
private List<String> names;
#EJB
private NameService nameService;
#PostConstruct
public void init() {
names = nameService.list();
}
// ... (getters, setters, etc)
}
Simple as that. Actually, the T's toString() will be used to represent both the dropdown item label and value. So, when you're instead of List<String> using a list of complex objects like List<SomeEntity> and you haven't overridden the class' toString() method, then you would see com.example.SomeEntity#hashcode as item values. See next section how to solve it properly.
Also note that the bean for <f:selectItems> value does not necessarily need to be the same bean as the bean for <h:selectOneMenu> value. This is useful whenever the values are actually applicationwide constants which you just have to load only once during application's startup. You could then just make it a property of an application scoped bean.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{data.names}" />
</h:selectOneMenu>
Complex objects as available items
Whenever T concerns a complex object (a javabean), such as User which has a String property of name, then you could use the var attribute to get hold of the iteration variable which you in turn can use in itemValue and/or itemLabel attribtues (if you omit the itemLabel, then the label becomes the same as the value).
Example #1:
<h:selectOneMenu value="#{bean.userName}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>
with
private String userName;
private List<User> users;
#EJB
private UserService userService;
#PostConstruct
public void init() {
users = userService.list();
}
// ... (getters, setters, etc)
Or when it has a Long property id which you would rather like to set as item value:
Example #2:
<h:selectOneMenu value="#{bean.userId}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>
with
private Long userId;
private List<User> users;
// ... (the same as in previous bean example)
Complex object as selected item
Whenever you would like to set it to a T property in the bean as well and T represents an User, then you would need to bake a custom Converter which converts between User and an unique string representation (which can be the id property). Do note that the itemValue must represent the complex object itself, exactly the type which needs to be set as selection component's value.
<h:selectOneMenu value="#{bean.user}" converter="#{userConverter}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
with
private User user;
private List<User> users;
// ... (the same as in previous bean example)
and
#ManagedBean
#RequestScoped
public class UserConverter implements Converter {
#EJB
private UserService userService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return userService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User ID", submittedValue)), e);
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return "";
}
if (modelValue instanceof User) {
return String.valueOf(((User) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);
}
}
}
(please note that the Converter is a bit hacky in order to be able to inject an #EJB in a JSF converter; normally one would have annotated it as #FacesConverter(forClass=User.class), but that unfortunately doesn't allow #EJB injections)
Don't forget to make sure that the complex object class has equals() and hashCode() properly implemented, otherwise JSF will during render fail to show preselected item(s), and you'll on submit face Validation Error: Value is not valid.
public class User {
private Long id;
#Override
public boolean equals(Object other) {
return (other != null && getClass() == other.getClass() && id != null)
? id.equals(((User) other).id)
: (other == this);
}
#Override
public int hashCode() {
return (id != null)
? (getClass().hashCode() + id.hashCode())
: super.hashCode();
}
}
Complex objects with a generic converter
Head to this answer: Implement converters for entities with Java Generics.
Complex objects without a custom converter
The JSF utility library OmniFaces offers a special converter out the box which allows you to use complex objects in <h:selectOneMenu> without the need to create a custom converter. The SelectItemsConverter will simply do the conversion based on readily available items in <f:selectItem(s)>.
<h:selectOneMenu value="#{bean.user}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
See also:
Our <h:selectOneMenu> wiki page
View-Page
<h:selectOneMenu id="selectOneCB" value="#{page.selectedName}">
<f:selectItems value="#{page.names}"/>
</h:selectOneMenu>
Backing-Bean
List<SelectItem> names = new ArrayList<SelectItem>();
//-- Populate list from database
names.add(new SelectItem(valueObject,"label"));
//-- setter/getter accessor methods for list
To display particular selected record, it must be one of the values in the list.
Roll-your-own generic converter for complex objects as selected item
The Balusc gives a very useful overview answer on this subject. But there is one alternative he does not present: The Roll-your-own generic converter that handles complex objects as the selected item. This is very complex to do if you want to handle all cases, but pretty simple for simple cases.
The code below contains an example of such a converter. It works in the same spirit as the OmniFaces SelectItemsConverter as it looks through the children of a component for UISelectItem(s) containing objects. The difference is that it only handles bindings to either simple collections of entity objects, or to strings. It does not handle item groups, collections of SelectItems, arrays and probably a lot of other things.
The entities that the component binds to must implement the IdObject interface. (This could be solved in other way, such as using toString.)
Note that the entities must implement equals in such a way that two entities with the same ID compares equal.
The only thing that you need to do to use it is to specify it as converter on the select component, bind to an entity property and a list of possible entities:
<h:selectOneMenu value="#{bean.user}" converter="selectListConverter">
<f:selectItem itemValue="unselected" itemLabel="Select user..."/>
<f:selectItem itemValue="empty" itemLabel="No user"/>
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
Converter:
/**
* A converter for select components (those that have select items as children).
*
* It convertes the selected value string into one of its element entities, thus allowing
* binding to complex objects.
*
* It only handles simple uses of select components, in which the value is a simple list of
* entities. No ItemGroups, arrays or other kinds of values.
*
* Items it binds to can be strings or implementations of the {#link IdObject} interface.
*/
#FacesConverter("selectListConverter")
public class SelectListConverter implements Converter {
public static interface IdObject {
public String getDisplayId();
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
return component.getChildren().stream()
.flatMap(child -> getEntriesOfItem(child))
.filter(o -> value.equals(o instanceof IdObject ? ((IdObject) o).getDisplayId() : o))
.findAny().orElse(null);
}
/**
* Gets the values stored in a {#link UISelectItem} or a {#link UISelectItems}.
* For other components returns an empty stream.
*/
private Stream<?> getEntriesOfItem(UIComponent child) {
if (child instanceof UISelectItem) {
UISelectItem item = (UISelectItem) child;
if (!item.isNoSelectionOption()) {
return Stream.of(item.getValue());
}
} else if (child instanceof UISelectItems) {
Object value = ((UISelectItems) child).getValue();
if (value instanceof Collection) {
return ((Collection<?>) value).stream();
} else {
throw new IllegalStateException("Unsupported value of UISelectItems: " + value);
}
}
return Stream.empty();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) return null;
if (value instanceof String) return (String) value;
if (value instanceof IdObject) return ((IdObject) value).getDisplayId();
throw new IllegalArgumentException("Unexpected value type");
}
}
I'm doing it like this:
Models are ViewScoped
converter:
#Named
#ViewScoped
public class ViewScopedFacesConverter implements Converter, Serializable
{
private static final long serialVersionUID = 1L;
private Map<String, Object> converterMap;
#PostConstruct
void postConstruct(){
converterMap = new HashMap<>();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
String selectItemValue = String.valueOf( object.hashCode() );
converterMap.put( selectItemValue, object );
return selectItemValue;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String selectItemValue){
return converterMap.get(selectItemValue);
}
}
and bind to component with:
<f:converter binding="#{viewScopedFacesConverter}" />
If you will use entity id rather than hashCode you can hit a collision- if you have few lists on one page for different entities (classes) with the same id
Call me lazy but coding a Converter seems like a lot of unnecessary work. I'm using Primefaces and, not having used a plain vanilla JSF2 listbox or dropdown menu before, I just assumed (being lazy) that the widget could handle complex objects, i.e. pass the selected object as is to its corresponding getter/setter like so many other widgets do. I was disappointed to find (after hours of head scratching) that this capability does not exist for this widget type without a Converter. In fact if you supply a setter for the complex object rather than for a String, it fails silently (simply doesn't call the setter, no Exception, no JS error), and I spent a ton of time going through BalusC's excellent troubleshooting tool to find the cause, to no avail since none of those suggestions applied. My conclusion: listbox/menu widget needs adapting that other JSF2 widgets do not. This seems misleading and prone to leading the uninformed developer like myself down a rabbit hole.
In the end I resisted coding a Converter and found through trial and error that if you set the widget value to a complex object, e.g.:
<p:selectOneListbox id="adminEvents" value="#{testBean.selectedEvent}">
... when the user selects an item, the widget can call a String setter for that object, e.g. setSelectedThing(String thingString) {...}, and the String passed is a JSON String representing the Thing object. I can parse it to determine which object was selected. This feels a little like a hack, but less of a hack than a Converter.

Measure the render time of a JSF view after a server request

I would like to measure the rendering time of a JSF application. Because of out of my power reasons, the application can't be populated with logs.
Therefore, my question would be, is there any way in which I can measure the rendering time of the application after doing a certain action that includes a back-end(server) call using any browser?
So far,after using the Chrome Developer Tools,I spotted the following. On the Network tab, each request has the "Time" displayed. In addition, after selecting a certain entry, on the "Timing" tab, a more detailed visualization it's displayed.
Now, I can tell from that that the "Waiting" that the round-trip to the server it's captured here, but what about the actual rendering time.
Assuming that the whole request took 1sec, and the Waiting section it's 500ms, can I deduct that the rendering it's the 1sec-500ms ? I assume not, thats why I am asking this question.
Long story short, I would need to know from the browser, for a certain request how long was the server processing and how long was the actual UI rendering.
Any tips would be greatly appreciated. Thank you.
You can do that with a custom ViewDeclarationLanguage whereby you measure the createView(), buildView(), renderView() and if necessary restoreView() methods.
Here's a kickoff example:
public class VdlLogger extends ViewDeclarationLanguageWrapper {
private static final Logger logger = Logger.getLogger(VdlLoggerFactory.class.getName());
private ViewDeclarationLanguage wrapped;
public VdlLogger(ViewDeclarationLanguage wrapped) {
this.wrapped = wrapped;
}
#Override
public UIViewRoot createView(FacesContext context, String viewId) {
long start = System.nanoTime();
UIViewRoot view = super.createView(context, viewId);
long end = System.nanoTime();
logger.info(String.format("create %s: %.6fms", viewId, (end - start) / 1e6));
return view;
}
#Override
public void buildView(FacesContext context, UIViewRoot view) throws IOException {
long start = System.nanoTime();
super.buildView(context, view);
long end = System.nanoTime();
logger.info(String.format("build %s: %.6fms", view.getViewId(), (end - start) / 1e6));
}
#Override
public void renderView(FacesContext context, UIViewRoot view) throws IOException {
long start = System.nanoTime();
super.renderView(context, view);
long end = System.nanoTime();
logger.info(String.format("render %s: %.6fms", view.getViewId(), (end - start) / 1e6));
}
#Override
public ViewDeclarationLanguage getWrapped() {
return wrapped;
}
}
To get it to run, create the below factory:
public class VdlLoggerFactory extends ViewDeclarationLanguageFactory {
private ViewDeclarationLanguageFactory wrapped;
public VdlLoggerFactory(ViewDeclarationLanguageFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewDeclarationLanguage getViewDeclarationLanguage(String viewId) {
return new VdlLogger(wrapped.getViewDeclarationLanguage(viewId));
}
#Override
public ViewDeclarationLanguageFactory getWrapped() {
return wrapped;
}
}
And register it as below in faces-config.xml:
<factory>
<view-declaration-language-factory>com.example.VdlLoggerFactory</view-declaration-language-factory>
</factory>
The createView() is the step of creating the concrete UIViewRoot instance based on <f:view> and <f:metadata> present in the view files. When using Facelets (XHTML) as view, during this step all associated XHTML files will be parsed by the SAX parser and cached for a time as defined in javax.faces.FACELETS_REFRESH_PERIOD. So it may happen that it's one time relatively slow and the other time blazing fast.
The buildView() is the step of populating the JSF component tree (the getChildren() of UIViewRoot) based on the view (XHTML) composition. During this step, all taghandlers (JSTL and friends) are executed and all EL expressions in those taghandlers and component's id and binding attributes are evaluated (for detail, see also JSTL in JSF2 Facelets... makes sense?). So if backing beans are constructed for first time during view build time and invoking business logic during #PostConstruct, then it may happen that this is time consuming.
The renderView() is the step of generating the HTML output based on JSF component tree and the model, starting with UIViewRoot#encodeAll(). So if backing beans are constructed for first time during view render time and invoking business logic during #PostConstruct, then it may happen that this is time consuming.
If backing beans are incorrectly performing business logic in getter methods instead of in #PostConstruct or any other one-time-occurring life cycle event listener, then it may happen that this consumes yet more time. See also Why JSF calls getters multiple times.

How to redirect xhtml page to the same Request Scoped Bean?

Since the bean is in Request Scope, redirect creates a new instance.
If I try to put the bean in the View Scope, then I get the error of Property name is referenced to object narrower than the target View.
I'm displaying a tree, and when the user clicks on the tree node, say the 2nd node, the values corresponding to that node is displayed on the next page.
#ManagedBean
#RequestScoped
public class ThreeSixtyDegreeBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#ManagedProperty(value="#{param.name1}")
private String name;
private String type;
private String typeName;
private List<AttributeDetails> attributeList;
private List<Entity> entityList;
private boolean rendered;
private TreeNode root;
private TreeNode selectedNode;
public void onNodeSelect() {
*selecting Data of the Node selected*
String a=fetchData();
try {
FacesContext.getCurrentInstance().getExternalContext()
.redirect(a);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Where a is name of the xhtml page.
You can stash your stuff in the new JSF 2 Flash Scope to stash attributes between requests. Your onNodeSelect() can now look like this :
public void onNodeSelect() {
*selecting Data of the Node selected*
FacesContext context = FacesContext.getCurrentInstance();
Flash flash = context.getCurrentInstance().getExternalContext().getFlash(); //prepare jsf flash scope, to store user data pojo for the next view
flash.putNow("myData", fetchData());
try {
FacesContext.getCurrentInstance().getExternalContext()
.redirect(a);
} catch (IOException e) {
e.printStackTrace();
}
}
}
On the destination page, you can then retrieve the data you stored in the flash scope using the #{flash} EL expression. It's essentially a Map so you just use the key of the value you stored ("myData" in the example I used above). to access it, use
#{flash.myData.someMemberVariable}
The view scope wouldn't have worked either. It lives as long as you're postbacking to the same view. A redirect basically creates a brand new GET request and would also have recreated the view scope.
In this particular case, you're better off performing data initialization in the redirected request, not in the postback request. You could do that by creating a normal GET link wherein you pass the necessary information as request parameters. Something like this:
<h:link value="#{node.name}" outcome="#{node.viewId}">
<f:param name="someId" value="#{node.someId}" />
<f:param name="name1" value="#{param.name1}" />
</h:link>
and then in the request scoped bean associated with the redirected page, you can just use #ManagedProperty or even the <f:viewParam> to set the request parameters as model values.
See also:
Communication in JSF 2.0 - Processing GET request parameters

Add a URL in faces message JSF 2.0 [duplicate]

I want to embed a link in a JSF message, is this possible?
When I try it, the rendered html of the h:messages tag escapes the html characters. I tried setting the escape attribute of the h:messages tag to false, but that didn't help.
Unfortunately, this is not possible in the standard JSF implementation. The component and the renderer doesn't officially support this attribute. You can however homegrow a renderer which handles this.
Since this is a pretty common requirement/wish, I thought to take a look what's all possible.
First some background information: JSF by default uses ResponseWriter#writeText() to write the tag body, which escapes HTML by default. We'd like to let it use ResponseWriter#write() instead like as with <h:outputText escape="false" />. We'd like to extend the MessagesRenderer of the standard JSF implementation and override the encodeEnd() method accordingly. But since the MessagesRenderer#encodeEnd() contains pretty a lot of code (~180 lines) which we prefer not to copypaste to just change one or two lines after all, I found it better to replace the ResponseWriter with a custom implementation with help of ResponseWriterWrapper wherein the writeText() is been overriden to handle the escaping.
So, I ended up with this:
package com.example;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.context.ResponseWriterWrapper;
import javax.faces.render.FacesRenderer;
import com.sun.faces.renderkit.html_basic.MessagesRenderer;
#FacesRenderer(componentFamily="javax.faces.Messages", rendererType="javax.faces.Messages")
public class EscapableMessagesRenderer extends MessagesRenderer {
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
final ResponseWriter originalResponseWriter = context.getResponseWriter();
try {
context.setResponseWriter(new ResponseWriterWrapper() {
#Override
public ResponseWriter getWrapped() {
return originalResponseWriter;
}
#Override
public void writeText(Object text, UIComponent component, String property) throws IOException {
String string = String.valueOf(text);
String escape = (String) component.getAttributes().get("escape");
if (escape != null && !Boolean.valueOf(escape)) {
super.write(string);
} else {
super.writeText(string, component, property);
}
}
});
super.encodeEnd(context, component); // Now, render it!
} finally {
context.setResponseWriter(originalResponseWriter); // Restore original writer.
}
}
}
In spite of the #FacesRenderer annotation, it get overriden by the default MessagesRenderer implementation. I suspect here a bug, so I reported issue 1748. To get it to work anyway, we have to fall back to the faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.Messages</component-family>
<renderer-type>javax.faces.Messages</renderer-type>
<renderer-class>com.example.EscapableMessagesRenderer</renderer-class>
</renderer>
</render-kit>
Then, to trigger it, just do:
<h:messages escape="false" />
And it works! :)
Note: the above affects <h:messages> only. To do the same for <h:message>, just do the same, but replace anywhere "Messages" by "Message" (component family, renderer type and classnames).
The escape="false" attributed you need is provided by the OmniFaces <o:messages> component. The OmniFaces utility library is available for JSF 2.
I posted this solution mentioned by #BalusC's comment as an answer since this is the most straightforward solution.

Putting parameters in velocity context in Jira 4.4

I'm developing a plugin to display additional information related to a project.
So I'm developing a Project Tab Panel module but my page does not display the paramenters I put in the velocity context.
Here is the a part of plugin xml:
<project-tabpanel key="stats-tab-panel" name="Stats Tab Panel" i18n-name-key="stats-tab-panel.name" class="it.pride.jira.plugins.StatsTabPanel">
<description key="stats-tab-panel.description">The Stats Tab Panel Plugin</description>
<label key="stats-tab-panel.label"></label>
<order>10</order>
<resource type="velocity" name="view" location="templates/tabpanels/stats-tab-panel.vm"/>
Here instead the useful part of my class:
public class StatsTabPanel extends GenericProjectTabPanel {
public StatsTabPanel(JiraAuthenticationContext jiraAuthenticationContext,
FieldVisibilityManager fieldVisibilityManager) {
super(jiraAuthenticationContext, fieldVisibilityManager);
// TODO Auto-generated constructor stub
}
public String testvalue="112002";
#Override
public boolean showPanel(BrowseContext context){
return true;
}
#Override
public Map<String, Object> createVelocityParams (BrowseContext context) {
Map<String, Object> contextMap = createVelocityParams(context);
contextMap.put("testvalue", testvalue);
return contextMap;
}
}
So, as in this case, when i write `$testvalue in my template the number doesn't show up.
What am I doing wrong?
The problem is that the getHtml method that is used to return the HTML for the tab has a Map that is the Velocity context but only contains the params in the BrowseContext object. The way to fix this is to override createVelocityParams in your class, e.g.
protected Map createVelocityParams(final BrowseContext ctx) {
Map params = super.createVelocityParams(ctx);
params.put("myparam", "some value for it");
return params;
}
The problem is that method is protected so I ended up also overriding getHtml which calls createVelocityParams in a parent class.
Some Project tabs extend GenericProjectTabPanel but some such as SummaryProjectTabPanel.java seem to use UI Fragments. I suspect that Fragments is what things are moving towards.

Resources