Override PrimeFaces' MediaRenderer - jsf

Im trying to override Primeface's 7.0 MediaRenderer, I created my own MyMediaRenderer with Primeface's 8.0 method:
public class MyMediaRenderer extends org.primefaces.component.media.MediaRenderer {
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
...
if (value instanceof StreamedContent && PDFPlayer.MIME_TYPE.equals(player.getType())) {
...
}
...
}
}
I also added to the end of src/main/webapp/WEB-INF/faces-config.xml :
<render-kit>
<renderer>
<component-family>org.primefaces.component.media</component-family>
<renderer-type>org.primefaces.component.media.MediaRenderer</renderer-type>
<renderer-class>redacted.MyMediaRenderer</renderer-class>
</renderer>
</render-kit>
</faces-config>
What am I missing here? The method is still called from org.primefaces.component.media.MediaRenderer

Your renderkit is incorrect use the following:
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.MediaRenderer</renderer-type>
<renderer-class>redacted.MyMediaRenderer</renderer-class>
</renderer>

Related

Adding an attribute to primefaces by extending commandButton component

Primefaces 8
Java 11
I would like to add a controller attribute to a commandButton which takes in page bean instance as value . I can then use this page bean in command button renderer to disable the button by calling method on page bean.
Component Bean class
#FacesComponent(CustomCommandButton.COMPONENT_TYPE)
public class CustomCommandButton extends CommandButton
{
private static final Logger logger = Logger.getInstance(CustomCommandButton.class);
public static final String COMPONENT_FAMILY = "com.xxx.faces.component";
public static final String COMPONENT_TYPE = "com.xxx.faces.component.CustomCommandButton";
private enum PropertyKeys {
controller
}
private IpmsBean controller;
#Override
public String getFamily() {
return COMPONENT_FAMILY;
}
#Override
public String getRendererType() {
return CustomCommandButtonRenderer.RENDERER_TYPE;
}
public CustomCommandButton()
{
super();
}
public void setController(IpmsBean bean)
{
getStateHelper().put(PropertyKeys.controller, bean);
this.controller=bean;
}
public IpmsBean getController()
{
return (IpmsBean) getStateHelper().eval(PropertyKeys.controller, null);
}
}
Renderer class which doesn't have whole lot just yet:
#FacesRenderer(
componentFamily=CustomCommandButton.COMPONENT_FAMILY,
rendererType=CustomCommandButtonRenderer.RENDERER_TYPE
)
public class CustomCommandButtonRenderer extends CommandButtonRenderer {
public static final String RENDERER_TYPE = "com.xxx.faces.component.CustomCommandButtonRenderer";
#Override
public void encodeEnd(FacesContext context, UIComponent component)
throws java.io.IOException {
//plan is to disable button after asking pagebean
//if (component.getController().shouldDisable())
// component.setDisabled("true");
//
super.encodeEnd(context, component);
}
}
taglibs-faces.xml
<?xml version="1.0"?>
<facelet-taglib version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
id="lu">
<namespace>http://com.xxx.faces/ui</namespace>
<tag>
<tag-name>customCommandButton</tag-name>
<component>
<component-type>com.xxx.faces.component.CustomCommandButton</component-type>
<renderer-type>com.xxx.faces.component.CustomCommandButtonRenderer</renderer-type>
</component>
<attribute>
<description>
<![CDATA[Any instance of IpmsBean.]]>
</description>
<name>controller</name>
<required>false</required>
<type>com.xxx.xxxx.client.jsf.bean.IpmsBean</type>
</attribute>
...copied rest of commandbutton's attributes here...
</tag>
</facelet-taglib>
xhtml page:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
template="/resources/layout/masterLayout.xhtml"
xmlns:c="http://xmlns.jcp.org/jsf/core"
xmlns:incl="http://java.sun.com/jsf/composite/includes"
xmlns:lu="http://com.xxx.faces/ui">
<lu:customCommandButton
value="Custom Button"
controller="#{regionPolicyBean}"
oncomplete="hello()"/>
....
</ui:composition>
"Custom Button" shows up just fine. But setController(bean) method is not valled. setOnComplete() method is called. Not sure what am I missing here.
I did refer to this answer Adding Custom Attributes to Primefaces Autocomplete Component in JSF but still not sure why setter is not being called.
Not a direct answer, but I don't see why you do this the hard way. You can simply do:
<p:commandButton ...>
<f:attribute name="controller" value="#{...}"/>
</p:commandButton>
and get controller from the component's attributes map.

Custom converter with attributes/injection not working with anymore after upgrade to JSF 2.3

I am trying to upgrade/use a custom converter that worked with JSF 2.2 (on Wildfly 13) to work on JSF 2.3 (with Mojarra 2.3.9.SP02 running on Wildfly 17.0.1)
The converter is used via its own tag defined in a tag library.
Everything's fine as long as no tag attributes are used. The attributes are just not set in the converter. The setters never get called.
But if I remove the managed = true from the converter the attributes are set but then the injection no longer works.
The converter is used like this:
<h:inputText id="text" value="#{welcome.text}">
<cdijsf:converterWithAttr id="myConverter" attr="myAttrValue" />
</h:inputText>
Tag library:
<facelet-taglib version="2.3"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_3.xsd">
<namespace>http://cdijsf.transdata.net/jsf</namespace>
<tag>
<tag-name>converterWithAttr</tag-name>
<converter>
<converter-id>cdijsf.ConverterWithAttr</converter-id>
</converter>
<attribute>
<name>attr</name>
<type>java.lang.String</type>
</attribute>
</tag>
</facelet-taglib>
And this is the converter code:
#Dependent
#FacesConverter(value = "cdijsf.ConverterWithAttr", managed = true)
public class ConverterWithAttr implements Converter<String> {
#Inject
private BeanManager beanManager;
private String attr;
public ConverterWithAttr() {
}
#PostConstruct
private void init() {
// If 'managed = true' beanManager is injected at this point.
// If 'managed = false' beanManager is null at this point
}
#Override
public String getAsObject(FacesContext context, UIComponent component, String value) {
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, String value) {
return value;
}
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
// If 'managed = true' setAttr is never called
// If 'managed = false' setAttr is called
this.attr = attr;
}
}
faces-config.xml:
<faces-config version="2.3"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
</faces-config>
And I also explicitly declare JSF 2.3 like this:
#FacesConfig(version = Version.JSF_2_3)
#ApplicationScoped
public class JsfConfiguration {
}
beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
version="2.0"
bean-discovery-mode="annotated">
</beans>

cdi bean injection for initialization code

I have a bean configured which have some initialization logic. I have annotated this bean using #ApplicationScoped annotation. But somehow, cdi is not picking this bean.
beans.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
</beans>
Bean file:
#ApplicationScoped
public class Initializer{
#Inject #ConfigProperty(name = "app.name")
private String appName;
#Inject #ConfigProperty(name = "app.token")
private String appToken;
#Inject #ConfigProperty(name = "app.version")
private String appVersion;
#PostConstruct
public void init() {
System.out.println("flow should come here....); //but this line does not execute.
}
}
Code to read config file:
#Exclude
public class ConfigurationFile implements PropertyFileConfig {
#Override
public String getPropertyFileName() {
String env = Util.getEnv();
switch (env) {
case "dev":
case "uat":
case "prod":
return "config/" + env + "/default.properties";
default:
return "config/default.properties";
}
}
#Override
public boolean isOptional() {
return false;
}
}
I am using:
cdiL: for dependency injection,
apache-deltaspike: for reading config file.
wildfly-swarm: server
I have got the solution to this problem.
Issue is solved by changing the method declaration as follows:
public void init(#Observes #Initialized(ApplicationScoped.class) Object init) {
//................code logic here................
}

#Specializes in Wildfly 10.1.0

We are trying to use alternative bean instance injection for our integration test suite deployed on a Wildfly 10.1.0 server.
According to the CDI 1.2 spec, a possible solution to do so would be to use the #Specializes annotation on an alternative deployed in the integration test archive only.
However, the default implementation is always injected. We tried #Specializes on managed beans, session beans, and tried to select the alternatives in the beans.xml file.
The following example illustrate the issue:
BeanInterface.java
public interface BeanInterface {
void work();
}
Implementation1.java
#Dependent
public class Implementation1 implements BeanInterface {
#Override
public void work() {
System.out.println("test 1");
}
}
Implementation2
#Dependent
#Alternative
#Specializes
public class Implementation2 extends Implementation1 {
#Override
public void work() {
System.out.println("test 2");
}
}
TestSingleton.java:
#Singleton
#Startup
public class TestSingleton {
#Inject
private BeanInterface beanInterface;
#PostConstruct
public void init() {
this.beanInterface.work();
}
}
Packaging these classes in a war (with a web.xml) and deploying on wildfly, the implementation 1 is always injected in the Stateless bean.
Wildfly 10.1.0 uses weld-2.3.SP2 which implements CDI 1.2.
Thanks,
Charly
Although it does not make the #Specializes annotation work as expected, this solution suggested by John Ament allows to inject the second Implementation.
Just change the #javax.enterprise.inject.Specializes annotation with #javax.annotation.Priority (and some value):
#Dependent
#Alternative
#Priority(100)
public class Implementation2 extends Implementation1 {
#Override
public void work() {
System.out.println("test 2");
}
}
Also missing in the OP question was the beans.xml (not web.xml) packaged in the WEB-INF:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>

Exclude resources in JSF

I'm using Primefaces. For some pages I want to exclude the resources which are included by primefacs, especially the theme resource.
<link type="text/css" rel="stylesheet" href="/context/javax.faces.resource/theme.css?ln=primefaces-owntheme" />
I try that with a SystemEventListener as following:
public class PrimeFacesResourceRemover implements javax.faces.event.SystemEventListener {
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot viewRoot = context.getViewRoot();
for (UIComponent resource : viewRoot.getComponentResources(context, "head")) {
Map<String, Object> attrs = resource.getAttributes();
String resourceLibrary = (String) attrs.get("library");
String resourceName = (String) attrs.get("name");
if ("primefaces-owntheme".equals(resourceLibrary) && "theme.css".equals(resourceName)) {
// Remove resource from view
context.getViewRoot().removeComponentResource(context, resource, HEAD);
}
}
}
/**
* {#inheritDoc}
*/
#Override
public boolean isListenerForSource(Object source) {
return (source instanceof UIViewRoot);
}
}
and in the faces-config.xml
<application>
<system-event-listener>
<system-event-listener-class>
com.mycompany.mavenproject1.PrimeFacesResourceRemover
</system-event-listener-class>
<system-event-class>
javax.faces.event.PostAddToViewEvent
</system-event-class>
</system-event-listener>
</application>
This works well, when I include a resouce on a page manually, but those not work with the resouces which are included by Primefaces. How can I remove those resouces?
The theme.css is not been added as a dynamic component resource, but it's been hardcoded in PrimeFaces' HeadRenderer. The OmniFaces CombinedResourceHandler was also struggling with this.
The solution is rather simple: override it with a custom HeadRenderer (without any #ResourceDependency on theme.css, of course!):
public class HeadRenderer extends Renderer {
#Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
context.getResponseWriter().startElement("head", component);
}
#Override
public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
// NOOP.
}
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
for (UIComponent resource : context.getViewRoot().getComponentResources(context, "head")) {
resource.encodeAll(context);
}
context.getResponseWriter().endElement("head");
}
}
Register it as follows in webapp's faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.Head</renderer-type>
<renderer-class>com.example.HeadRenderer</renderer-class>
</renderer>
</render-kit>
For all of you who would like to remove theme.css on all pages (that's the first thing I am doing), and still don't know this trick.
You'll need to drop these few lines in your web.xml:
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>none</param-value>
</context-param>

Resources