with a lot of developers and plenty of juniors I want to disable certain components such as <p:spacer> to prohibit using components for html/css issues. I want to limit the available components for libraries like omnifaces / primefaces / richfaces to a whitelist / blacklist thing basically.
Would this be a reasonable feature request for a library like omnifaces or is it to hard to build / to localized?
Basically, you can achieve this by providing a custom Application implementation (based on ApplicationWrapper) wherein you override the desired createComponent() method and throw e.g. IllegalArgumentException when a blacklisted component type and/or renderer type is passed.
Here's a kickoff example:
public class YourApplication extends ApplicationWrapper {
private static final Set<String> BLACKLISTED_COMPONENT_TYPES = unmodifiableSet(new HashSet<>(asList(
"org.primefaces.component.Spacer",
"com.example.SomeComponentType",
"com.example.OtherComponentType"
// Etc..
)));
private final Application wrapped;
public YourApplication(Application wrapped) {
this.wrapped = wrapped;
}
#Override
public UIComponent createComponent(FacesContext context, String componentType, String rendererType) {
if (BLACKLISTED_COMPONENT_TYPES.contains(componentType)) {
throw new IllegalArgumentException("You are not allowed to use this component.");
}
return super.createComponent(context, componentType, rendererType);
}
#Override
public Application getWrapped() {
return wrapped;
}
}
You can get it to run with this factory:
public class YourApplicationFactory extends ApplicationFactory {
private final ApplicationFactory wrapped;
public YourApplicationFactory(ApplicationFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public Application getApplication() {
return new YourApplication(wrapped.getApplication());
}
#Override
public void setApplication(Application application) {
wrapped.setApplication(application);
}
}
Which is registered in faces-config.xml as below:
<factory>
<application-factory>com.example.YourApplicationFactory</application-factory>
</factory>
You can use tag file feature of jsf. You will declare tag file for each component that you want to use. After that, your team will only use these tag file in your project.
Related
My ASP.NET Core application is using dotliquid. I am creating my own custom dotliquid tag and I want to inject IHttpContextAccessor in my custom tag. Based on my research i have to create ITagFactory to create tag and inject IHttpContextAccessor.
my custom factory
public class LiquidTagFactory : DotLiquid.ITagFactory
{
private readonly Type _tagType;
private readonly string _tagName;
private readonly IHttpContextAccessor _contextAccessor;
public string TagName { get { return _tagName; } }
public LiquidTagFactory(Type tagType, string tagName, IHttpContextAccessor contextAccessor)
{
_tagType = tagType;
_tagName = tagName;
_contextAccessor = contextAccessor;
}
public Tag Create()
{
return (Tag)Activator.CreateInstance(_tagType, _contextAccessor);
}
}
my custom tag
public class TextBox : DotLiquid.Tag
{
private string _html = null;
private readonly IHttpContextAccessor _contextAccessor;
public TextBox(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public override void Initialize(string tagName, string markup, List<string> tokens)
{
// here i want to store some values into HttpContext.Items
_contextAccessor.HttpContext.Items.Add("key","somedata");
base.Initialize(tagName, markup, tokens);
}
public override void Render(Context context, TextWriter result)
{
_html = CreateHtml();
result.Write(_html);
base.Render(context, result);
}
}
Then i would register this factory as
Template.RegisterTagFactory(new LiquidTagFactory(typeof(TexBox), "textbox", _httpContextAccessor));
However, i am using ASP.NET Core. I am not sure how do i register custom tag factory using .NET Core's dependency injection?
looking at dotliquid's template code it stores the ITagFactory in private static field
private static Dictionary<string, Tuple<ITagFactory, Type>> Tags { get; set;}
In my case, every request will have its own IHttpContextAccessor, and i don't want to create factory for each request
I think i found it. As per SO we can register IHttpContextAccessor singleton.
As of .NET Core 2.1 there is an extension method that has been added to correctly register an IHttpContextAccessor as a singleton. Simply add as follows in your ConfigureServices() method:
services.AddHttpContextAccessor();
This is equivalent to:
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
and then register the factory in Configure() method in startup. Make sure to pass IHttpContextAccessor as parameter
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IOptions<DomainOptions> domainOps, IHttpContextAccessor httpContextAccessor)
{
Template.RegisterTagFactory(new LiquidTagFactory(typeof(TextBox), "textbox", httpContextAccessor));
}
I am able to successfully get this to work with the template in my app:
<ui:decorate template="/WEB-INF/templates/mytemplate.xhtml">
I am also able to move template to /META-INF/templates/mytemplate.xhtml of a JAR and get this to work:
<ui:decorate template="/templates/mytemplate.xhtml">
I would actually like to put this file onto filesystem (or database for that matter). How can I achieve this? I found plenty of things related to com.sun.facelets.impl.DefaultResourceResolver, but I don't think that is actually related to override the serving of the template. It is not trying resolve a URL, it is simply trying to get the file somehow on the classpath.
If you're already on JSF 2.2, you can do this by providing a custom ResourceHandler wherein you return the desired view resource in createViewResource().
public class FaceletsResourceHandler extends ResourceHandlerWrapper {
private ResourceHandler wrapped;
public FaceletsResourceHandler(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewResource createViewResource(FacesContext context, final String name) {
ViewResource resource = super.createViewResource(context, name);
if (resource == null) {
resource = new ViewResource() {
#Override
public URL getURL() {
try {
return new File("/some/base/path", name).toURI().toURL();
} catch (MalformedURLException e) {
throw new FacesException(e);
}
}
};
}
return resource;
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
}
Which is registered in faces-config.xml as below:
<application>
<resource-handler>com.example.FaceletsResourceHandler</resource-handler>
</application>
Or if you're not on JSF 2.2 yet, then use ResourceResolver instead.
public class FaceletsResourceResolver extends ResourceResolver {
private ResourceResolver parent;
public FaceletsResourceResolver(ResourceResolver parent) {
this.parent = parent;
}
#Override
public URL resolveUrl(String path) {
URL url = parent.resolveUrl(path); // Resolves from WAR.
if (url == null) {
try {
url = new File("/some/base/path", path).toURI().toURL();
} catch (MalformedURLException e) {
throw new FacesException(e);
}
}
return url;
}
}
Which is registered in web.xml as below:
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>
Regardless of the way, in order to provide the resource from the database, you'd either save/cache them on (temp) disk file system so you can provide the URL just via File, or invent a custom protocol such as db:// and provide a custom URLStreamHandlerFactory and URLStreamHandler implementation to perform the actual job of streaming from the DB. You can find a kickoff example here Registering and using a custom java.net.URL protocol.
I have Stateless bean that calls asynchronous operation. I would like to inject to this bean my another bean, which stores (or rather should store) running process status. Here is my code:
Processor:
#Stateless
public class Processor {
#Asynchronous
public void runLongOperation() {
System.out.println("Operation started");
try {
for (int i = 1; i <= 10; i++) {
//Status update goes here...
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
System.out.println("Operation finished");
}
}
ProcessorHandler:
#ManagedBean(eager = true, name="ph")
#ApplicationScoped
public class ProcessorHandler implements RemoteInterface {
public String status;
#EJB
private Processor processor;
#PostConstruct
public void init(){
status = "Initialized";
}
#Override
public void process() {
processor.runLongOperation();
}
public String getStatus() {
return status;
}
}
Process method of ProcessHandler is bound to a button.
I would like to modify status of ProcessHandler bean from inside of Processor, so I can display updated status to user.
I tried to use #Inject, #ManagedProperty and #EJB annotations, but without success.
I'm testing my soulution on Websphere v8.5 developed using Eclipse EE.
When added inject to Processor class...
#Inject
public ProcessorHandler ph;
I got error:
The #Inject java.lang.reflect.Field.ph reference of type ProcessorHandler for the <null> component in the Processor.war module of the ProcessorEAR application cannot be resolved.
You should never have any client-specific artifacts (JSF, JAX-RS, JSP/Servlet, etc) in your service layer (EJB). It makes the service layer unreusable across different clients/front-ends.
Simply move private String status field into the EJB as it's actually the one responsible for managing it.
#ManagedBean(eager = true, name="ph")
#ApplicationScoped
public class ProcessorHandler implements RemoteInterface {
#EJB
private Processor processor;
#Override
public void process() {
processor.runLongOperation();
}
public String getStatus() {
return processor.getStatus();
}
}
Note that this won't work on a #Stateless, but on #Singleton or Stateful only for the obvious reasons.
I'm trying to implement a Custom Naviguation, that do the usual job and update my breadcrumb.
public class CustomNaviguationHandler extends NavigationHandlerImpl{
public void handleNavigation(FacesContext context, String fromAction, String outcome) {
//do the breadcrumb update
super.handleNavigation(context, fromAction, outcome);
}
}
But when I debug it, the method is executed 2 times once,
The 1st time, fromAction and outcome are null
The 2nd time, these parameters contains the right values.
The handler has been registered in the faces-config.xml
<navigation-handler>my.package.CustomNaviguationHandler</navigation-handler>
I'm not sure to understant why? Any Idea?
You should not extend the JSF impl class NavigationHandlerImpl at all. You should instead extend the JSF API class NavigationHandler.
Here's a kickoff example. Do your job in the handleNavigation() method. If you don't want to take responsibility on navigation, delegate to the parent.
public class CustomNavigationHandler extends NavigationHandler {
private NavigationHandler parent;
public CustomNavigationHandler(NavigationHandler parent) {
this.parent = parent;
}
#Override
public void handleNavigation(FacesContext context, String from, String outcome) {
parent.handleNavigation(context, from, outcome);
}
}
I'm trying to intercept the method persist and update of javax.persistence.EntityManager in a Seam 3 project.
In a previous version (Seam 2) of the micro-framework I'm trying to make, I did this using an implementation of org.hibernate.Interceptor and declaring it in the persistence.xml.
But I want something more "CDI-like" now we are in a JEE6 environment.
I want that just before entering in a EntityManager.persist call, an event #BeforeTrackablePersist is thrown. The same way, I want an event #BeforeTrackableUpdate to be thrown before entering in a EntityManager.merge call. Trackable is an interface which some of my Entitys could implement in order to be intercepted before persist or merge.
I'm using Seam 3 (3.1.0.Beta3) Extended Persistence Manager :
public class EntityManagerHandler {
#SuppressWarnings("unused")
#ExtensionManaged
#Produces
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
}
So I've made a javax.enterprise.inject.spi.Extension, and tryied many ways to do that :
public class TrackableExtension implements Extension {
#Inject #BeforeTrackablePersisted
private Event<Trackable> beforeTrackablePersistedEvent;
#Inject #BeforeTrackableMerged
private Event<Trackable> beforeTrackableMergedEvent;
#SuppressWarnings("unchecked")
public void processEntityManagerTarget(#Observes final ProcessInjectionTarget<EntityManager> event) {
final InjectionTarget<EntityManager> injectionTarget = event.getInjectionTarget();
final InjectionTarget<EntityManager> injectionTargetProxy = (InjectionTarget<EntityManager>) Proxy.newProxyInstance(event.getClass().getClassLoader(), new Class[] {InjectionTarget.class}, new InvocationHandler() {
#Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
if ("produce".equals(method.getName())) {
final CreationalContext<EntityManager> ctx = (CreationalContext<EntityManager>) args[0];
final EntityManager entityManager = decorateEntityManager(injectionTarget, ctx);
return entityManager;
} else {
return method.invoke(injectionTarget, args);
}
}
});
event.setInjectionTarget(injectionTargetProxy);
}
public void processEntityManagerType(#Observes final ProcessAnnotatedType<EntityManager> event) {
final AnnotatedType<EntityManager> type = event.getAnnotatedType();
final AnnotatedTypeBuilder<EntityManager> builder = new AnnotatedTypeBuilder<EntityManager>().readFromType(type);
for (final AnnotatedMethod<? super EntityManager> method : type.getMethods()) {
final String name = method.getJavaMember().getName();
if (StringUtils.equals(name, "persist") || StringUtils.equals(name, "merge")) {
builder.addToMethod(method, TrackableInterceptorBindingLiteral.INSTANCE);
}
}
event.setAnnotatedType(builder.create());
}
public void processEntityManagerBean(#Observes final ProcessBean<EntityManager> event) {
final AnnotatedType<EntityManager> annotatedType = (AnnotatedType<EntityManager>)event.getAnnotated();
// not even called
}
public void processEntityManager(#Observes final ProcessProducer<?, EntityManager> processProducer) {
processProducer.setProducer(decorate(processProducer.getProducer()));
}
private Producer<EntityManager> decorate(final Producer<EntityManager> producer) {
return new Producer<EntityManager>() {
#Override
public EntityManager produce(final CreationalContext<EntityManager> ctx) {
return decorateEntityManager(producer, ctx);
}
#Override
public Set<InjectionPoint> getInjectionPoints() {
return producer.getInjectionPoints();
}
#Override
public void dispose(final EntityManager instance) {
producer.dispose(instance);
}
};
}
private EntityManager decorateEntityManager(final Producer<EntityManager> producer, final CreationalContext<EntityManager> ctx) {
final EntityManager entityManager = producer.produce(ctx);
return (EntityManager) Proxy.newProxyInstance(entityManager.getClass().getClassLoader(), new Class[] {EntityManager.class}, new InvocationHandler() {
#Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
final String methodName = method.getName();
if (StringUtils.equals(methodName, "persist")) {
fireEventIfTrackable(beforeTrackablePersistedEvent, args[0]);
} else if (StringUtils.equals(methodName, "merge")) {
fireEventIfTrackable(beforeTrackableMergedEvent, args[0]);
}
return method.invoke(entityManager, args);
}
private void fireEventIfTrackable(final Event<Trackable> event, final Object entity) {
if (entity instanceof Trackable) {
event.fire(Reflections.<Trackable>cast(entity));
}
}
});
}
}
In all those observer methods, only the second one (processEntityManagerType(#Observes ProcessAnnotatedType<EntityManager>)) is called ! And even with that binding addition to methods persist and merge, my Interceptor is never called (I've of course enabled it with the correct lines in beans.xml, and enabled my extension with the services/javax.enterprise.inject.spi.Extension file).
Something I've thought simple with CDI seems to be actually really hard at last... or perhaps Seam 3 does something which prevent this code from executing correctly...
Does someone know how to handle that ?
I think you're making this a little harder than what it needs to be. Firstly though, JPA and CDI integration isn't very good in Java EE 6, we're very much hoping that changes in Java EE 7 and JPA 2.1.
What you'll want to do is create your own producer for the EntityManager that will delegate to an actual instance of an EntityManager, but also fire your own events when you call the methods you're interested in. Take a look at the Seam Persistence source to see one way this can be done.
As finally my little patch for Seam Persistence was applied in SEAMPERSIST-75, it will be possible in theory to do that by extending org.jboss.seam.persistence.HibernatePersistenceProvider and override the method proxyEntityManager(EntityManager).