This is an automated email from the ASF dual-hosted git repository.

doebele pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/empire-db.git


The following commit(s) were added to refs/heads/master by this push:
     new 86f214f1 EMPIREDB-424 Allow programmatic Faces Configuration
86f214f1 is described below

commit 86f214f1ed5e7c7ec14b4d6c330934db91fa0968
Author: Rainer Döbele <[email protected]>
AuthorDate: Sun Apr 21 14:57:58 2024 +0200

    EMPIREDB-424
    Allow programmatic Faces Configuration
---
 .../apache/empire/jsf2/app/FacesConfiguration.java | 578 +++++++++++++++++++++
 .../empire/jsf2/app/WebAppStartupListener.java     |  36 +-
 .../org/apache/empire/jsf2/app/WebApplication.java |   4 +-
 .../java/org/apache/empire/commons/ClassUtils.java |  95 +++-
 ...ErrorException.java => MiscErrorException.java} |   6 +-
 5 files changed, 703 insertions(+), 16 deletions(-)

diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/FacesConfiguration.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/FacesConfiguration.java
new file mode 100644
index 00000000..186e1353
--- /dev/null
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/FacesConfiguration.java
@@ -0,0 +1,578 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.jsf2.app;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.el.ELResolver;
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.NavigationHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.event.PhaseListener;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.render.Renderer;
+
+import org.apache.empire.commons.ClassUtils;
+import org.apache.empire.commons.StringUtils;
+import org.apache.empire.exceptions.InternalException;
+import org.apache.empire.exceptions.InvalidArgumentException;
+import org.apache.empire.exceptions.ItemExistsException;
+import org.apache.empire.exceptions.ItemNotFoundException;
+import org.apache.empire.exceptions.ObjectNotValidException;
+import org.apache.empire.exceptions.UnspecifiedErrorException;
+import org.apache.empire.jsf2.impl.FacesImplementation;
+import org.apache.empire.jsf2.pages.PageNavigationHandler;
+import org.apache.empire.jsf2.pages.PagePhaseListener;
+import org.apache.empire.jsf2.pages.PagesELResolver;
+import org.apache.myfaces.cdi.util.BeanEntry;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.spi.InjectionProvider;
+import org.apache.myfaces.spi.InjectionProviderException;
+import org.apache.myfaces.spi.InjectionProviderFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * FacesConfiguration
+ * Allows programmatic Faces configuration as an alternative to the 
faces-config.xml
+ * In order to provide custom configuration you must override the class 
WebAppStartupListener
+ * and put it in the faces-config.xml
+ * <pre> 
+ *   
<system-event-listener-class>de.volkswagen.jsf.FacesStartupListener</system-event-listener-class>
+ * </pre>
+ * Further you must call the super constructor with a FacesConfiguration class 
like this:
+ * <pre>
+ *   public FacesStartupListener()
+ *   {
+ *      super(FacesExtensions.class);
+ *   }
+ * </pre> 
+ */
+public class FacesConfiguration
+{
+    protected static final Logger log = 
LoggerFactory.getLogger(FacesConfiguration.class);
+    
+    /*
+     * Initialized
+     */
+    private static boolean initialized = false;
+    public static boolean isInitialized()
+    {
+        return initialized; 
+    }
+
+    /*
+     * Project Stage
+     */
+    private static final String PROJECT_STAGE_PARAM = 
"javax.faces.PROJECT_STAGE";
+    private static String projectStage;
+    public static String getProjectStage()
+    {
+        if (projectStage==null)
+            throw new ObjectNotValidException(FacesConfiguration.class, "Not 
Initialized");
+        return projectStage;
+    }
+    
+    /**
+     * Static Initializer
+     * @param clazz
+     * @param context
+     */
+    public static <T extends FacesConfiguration> void initialize(Class<T> 
configClass, FacesContext context, FacesImplementation facesImpl)
+    {
+        if (initialized)
+            throw new UnspecifiedErrorException("FacesConfiguration already 
initialized!"); 
+        try
+        { // Create Instance an initialize
+            FacesConfiguration fConfig = configClass.newInstance();
+            fConfig.facesImpl = facesImpl;
+            fConfig.initialize(context);
+            initialized = true;
+        }
+        catch (InstantiationException | IllegalAccessException e)
+        {
+            throw new InternalException(e);
+        }
+    }
+
+    protected FacesImplementation facesImpl;
+
+    /*
+     * Temp Variables
+     */
+    protected Application application;
+    protected RuntimeConfig runtimeConfig;
+    protected BeanStorageProvider beanStorage;
+
+    public FacesConfiguration()
+    {
+        // Nothing
+    }
+
+    public final void initialize(FacesContext context)
+    {
+        try
+        {   // Set temporary variables
+            ExternalContext externalContext = context.getExternalContext();
+            this.application = context.getApplication();
+            this.runtimeConfig = 
RuntimeConfig.getCurrentInstance(externalContext);
+            this.beanStorage = new BeanStorageProvider(externalContext);
+            
+            // Set ProjectStage
+            projectStage = 
externalContext.getInitParameter(PROJECT_STAGE_PARAM);
+            log.info("Initializing Faces Configuration for {}", projectStage);
+            
+            initAll(context);
+
+            // done
+            log.info("Faces Configuration complete");
+        }
+        finally
+        {   // cleanup
+            this.beanStorage = null;
+            this.runtimeConfig = null;
+            this.application = null;
+        }
+    }
+    
+    /*
+     * Overrideable methods
+     */
+    
+    protected void initAll(FacesContext context)
+    {
+        log.info("Init NavigationHandler...");
+        initNavigationHandler();
+        
+        log.info("Init ResourceHandler...");
+        initResourceHandler();
+
+        log.info("Registrating Converters...");
+        initConverters();
+
+        log.info("Registrating EL-Resolvers...");
+        initElResolvers();
+        
+        log.info("Registrating Lifecycle...");
+        initLifecycle(new LifecycleUpdater(beanStorage));
+
+        log.info("Registrating Search Expression Resolvers...");
+        initSearchExpressionResolvers();
+
+        log.info("Registrating Components...");
+        initComponents();
+
+        log.info("Registrating Renderers...");
+        initRenderers(new RenderKitUpdater(getApplicationRenderKit(context)));
+
+        log.info("Registrating Managed Beans...");
+        initManagedBeans();            
+
+        log.info("Registrating Controls...");
+        initControls();
+    }
+    
+    protected void initNavigationHandler()
+    {
+        NavigationHandler wrapped = application.getNavigationHandler();
+        if (wrapped instanceof PageNavigationHandler)
+            return; // Already set
+        // replace
+        log.info("Setting NavigationHandler to {}", 
PageNavigationHandler.class.getName());
+        application.setNavigationHandler(new PageNavigationHandler(wrapped));
+    }
+    
+    protected void initResourceHandler()
+    {
+        // Not implemented
+        // application.setResourceHandler(new MyResourceHandler(wrapped));
+    }
+
+    protected void initConverters()
+    {
+        // Noting
+    }
+
+    protected void initElResolvers()
+    {
+        addELResolver(DBELResolver.class);
+        addELResolver(PagesELResolver.class);
+    }
+    
+    protected void initLifecycle(LifecycleUpdater lcu)
+    {
+        lcu.addPhaseListener(FacesRequestPhaseListener.class);
+        lcu.addPhaseListener(PagePhaseListener.class);
+    }
+
+    protected void initSearchExpressionResolvers()
+    {
+        // Nothing
+        // SearchExpressionResolverFactory.registerResolver("@fragment", new 
FragmentExpressionResolver());
+    }
+
+    protected void initComponents()
+    {
+        // Empire Components
+        String EMPIRE_FAMILY = "org.apache.empire.component";
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.ControlTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.InputTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.FormGridTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.LabelTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.LinkTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.MenuItemTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.MenuListTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.RecordTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.SelectTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.TabPageTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.TabViewTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.TitleTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.UnitTag.class);
+        addComponent(EMPIRE_FAMILY, 
org.apache.empire.jsf2.components.ValueTag.class);
+    }
+
+    protected void initRenderers(RenderKitUpdater rku)
+    {
+        // Noting
+        // rku.replace("javax.faces.Input", "javax.faces.Text", 
FacesTextInputRenderer.class);
+    }
+    
+    protected void initManagedBeans()
+    {
+        // Nothing
+        // addManagedBean(ConfirmPopup.MANAGED_BEAN_NAME, ConfirmPopup.class, 
ConfirmPopup.MANAGED_BEAN_SCOPE);
+    }
+
+    protected void initControls()
+    {
+        // Not implemented
+        // InputControlManager.registerControl(new 
CustomCheckboxInputControl());
+    }
+
+    /*
+     *  Helpers 
+     */
+    
+    protected RenderKit getApplicationRenderKit(FacesContext context)
+    {
+        String renderKitId = application.getDefaultRenderKitId(); 
+        return 
((RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY)).getRenderKit(context,
 renderKitId);
+    }
+    
+    protected void addConverter(Class<?> targetClass, Class<? extends 
Converter> converterClass)
+    {
+        log.info("Adding Type-Converter for type \"{}\" using {}", 
targetClass.getName(), converterClass.getName());
+        application.addConverter(targetClass, converterClass.getName());
+    }
+
+    protected void addComponent(String componentFamily, Class<? extends 
UIComponent> clazz)
+    {
+        String type = StringUtils.concat(componentFamily, ".", 
clazz.getSimpleName());
+        log.info("Adding component type \"{}\" using {}", type, 
clazz.getName());
+        application.addComponent(type, clazz.getName());
+    }
+    
+    protected void addManagedBean(String beanName, Class<?> beanClass, String 
scope)
+    {
+        facesImpl.registerManagedBean(beanName, beanClass.getName(), scope);
+    }
+
+    protected void replaceComponent(Class<? extends UIComponent> 
primeComponent, Class<? extends UIComponent> overrideComponent)
+    {
+        String type = (String) ClassUtils.getFieldValue(primeComponent, null, 
"COMPONENT_TYPE", true);
+        if (StringUtils.isEmpty(type))
+            throw new InvalidArgumentException("primeComponent", 
primeComponent.getName());
+        // check
+        checkComponentTypeExists(type);
+        log.info("Replacing component type \"{}\" with {}", type, 
overrideComponent.getName());
+        application.addComponent(type, overrideComponent.getName());
+    }
+    
+    protected void checkComponentTypeExists(String componentType)
+    {
+        Iterator<String> types = application.getComponentTypes();
+        while (types.hasNext())
+        {
+            String type = types.next();
+            if (componentType.equals(type))
+                return; // found;
+        }
+        throw new ItemNotFoundException("Component-Type: "+componentType);
+    }
+    
+    protected void addELResolver(Class<? extends ELResolver> resolverClass)
+    {
+        List<ELResolver> list = runtimeConfig.getFacesConfigElResolvers();
+        if (list!=null) {
+            for (ELResolver resolver : list)
+            {
+                if (resolver.getClass().equals(resolverClass))
+                    return; // already there
+            }
+        }
+        log.info("Adding FacesConfigElResolver {}", resolverClass.getName());
+        ELResolver elResolver = ClassUtils.newInstance(resolverClass);
+        // Add to bean storage
+        beanStorage.injectBean(elResolver);
+        // Add to RuntimeConfig
+        runtimeConfig.addFacesConfigElResolver(elResolver);
+    }
+    
+    /*
+     * list
+     */
+    protected void listCompoennts()
+    {
+        ConfigTypeList list = new ConfigTypeList("Component-Types");
+        Iterator<String> types = application.getComponentTypes();
+        while (types.hasNext())
+        {
+            String componentType = types.next();
+            // log.info("Renderer-Family: {} Type {}", componentFamily, 
rendererType);
+            list.addItem(componentType);
+        }
+        log.info(list.toString());
+    }
+    
+    /**
+     * RenderKitReplacer
+     * @author doebele
+     */
+    protected static class RenderKitUpdater
+    {
+        private final RenderKit renderKit;
+        public RenderKitUpdater(RenderKit renderKit)
+        {
+            this.renderKit = renderKit;            
+        }
+        
+        public RenderKit getRenderKit()
+        {
+            return renderKit;
+        }
+
+        public void listAll()
+        {   // list all
+            ConfigTypeList list = new ConfigTypeList("Renderer-Types");
+            Iterator<String> families = renderKit.getComponentFamilies();
+            while (families.hasNext())
+            {
+                String componentFamily = families.next();
+                Iterator<String> types = 
renderKit.getRendererTypes(componentFamily);
+                while (types.hasNext())
+                {
+                    String rendererType = types.next();
+                    // log.info("Renderer-Family: {} Type {}", 
componentFamily, rendererType);
+                    list.addItem(componentFamily, rendererType);
+                }
+            }
+            log.info(list.toString());
+        }
+
+        public void add(String componentFamily, String rendererType, Class<? 
extends Renderer> rendererClass)
+        {
+            Renderer check = findRenderer(componentFamily, rendererType);
+            if (check!=null)
+            {   if (check.getClass().equals(rendererClass))
+                    return; // already there
+                // Another renderer exists
+                throw new 
ItemExistsException(StringUtils.concat(componentFamily, " / ", rendererType));
+            }
+            // add
+            log.info("Adding Renderer type \"{}\" using {}", rendererType, 
rendererClass.getName());
+            renderKit.addRenderer(componentFamily, rendererType, 
ClassUtils.newInstance(rendererClass));
+        }
+
+        public void replace(String componentFamily, String rendererType, 
Class<? extends Renderer> replaceClass)
+        {
+            // checkRenderTypeExists(componentFamily, rendererType);
+            Renderer check = findRenderer(componentFamily, rendererType);
+            if (check==null)
+                throw new 
ItemNotFoundException(StringUtils.concat(componentFamily, " / ", rendererType));
+            if (check.getClass().equals(replaceClass))
+                return; // Already replaced
+            // replace
+            log.info("Replacing Renderer type \"{}\" with class {}", 
rendererType, replaceClass.getName());
+            renderKit.addRenderer(componentFamily, rendererType, 
ClassUtils.newInstance(replaceClass));
+        }
+        
+        /*
+        public void replace(Class<? extends CoreRenderer> orgClass, Class<? 
extends CoreRenderer> replaceClass)
+        {
+            String name = orgClass.getName();
+            int sep = name.lastIndexOf('.');
+            replace(name.substring(0, sep), name.substring(sep+1), 
replaceClass);
+        }
+        */
+        
+        private Renderer findRenderer(String componentFamily, String 
rendererType)
+        {
+            // list all
+            Iterator<String> families = renderKit.getComponentFamilies();
+            while (families.hasNext())
+            {
+                String family = families.next();
+                if (componentFamily.equals(family)) {
+                    Iterator<String> types = 
renderKit.getRendererTypes(family);
+                    while (types.hasNext())
+                    {
+                        String type = types.next();
+                        if (rendererType.equals(type))
+                            return renderKit.getRenderer(componentFamily, 
rendererType); // found
+                    }
+                }
+            }
+            return null;
+        }
+        
+    }
+
+    /**
+    * BeanStorageProvider
+    * @author doebele
+    */
+    protected static class BeanStorageProvider
+    {
+        private final List<BeanEntry> injectedBeanStorage;
+        private final InjectionProvider injectionProvider;
+
+        @SuppressWarnings("unchecked")
+        public BeanStorageProvider(ExternalContext ec)
+        {
+           this.injectionProvider = 
InjectionProviderFactory.getInjectionProviderFactory(ec).getInjectionProvider(ec);
+           final String INJECTED_BEAN_STORAGE_KEY = 
"org.apache.myfaces.spi.BEAN_ENTRY_STORAGE";
+           this.injectedBeanStorage = 
(List<BeanEntry>)ec.getApplicationMap().get(INJECTED_BEAN_STORAGE_KEY);
+           if (this.injectedBeanStorage==null)
+               throw new ItemNotFoundException(INJECTED_BEAN_STORAGE_KEY);
+        }
+        
+        public void injectBean(Object bean)
+        {   try
+            {   // Add to bean storage
+                Object creationMetaData = injectionProvider.inject(bean);
+                injectedBeanStorage.add(new BeanEntry(bean, creationMetaData));
+                injectionProvider.postConstruct(bean, creationMetaData);
+            }
+            catch (InjectionProviderException e)
+            {
+                throw new InternalException(e);
+            }
+        }
+    }
+    
+    /**
+    * LifecycleUpdater
+    * @author doebele
+    */
+    protected static class LifecycleUpdater
+    {
+        private final BeanStorageProvider beanStorage;
+        private final Lifecycle lifecycle;
+        private PhaseListener[] phaseListeners;
+
+        public LifecycleUpdater(BeanStorageProvider beanStorage)
+        {
+           this.beanStorage = beanStorage;
+           // The DEFAULT Lifecycle
+           LifecycleFactory lifecycleFactory = (LifecycleFactory) 
FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); 
+           this.lifecycle = 
lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+           this.phaseListeners = lifecycle.getPhaseListeners();
+        }
+
+        public void listAll()
+        {
+            ConfigTypeList list = new ConfigTypeList("Phase-Listeners");
+            this.phaseListeners = lifecycle.getPhaseListeners();
+            for (PhaseListener pl : phaseListeners)
+            {
+                list.addItem(pl.getClass(), pl.getPhaseId());
+            }
+            log.info(list.toString());
+        }
+
+        public void addPhaseListener(Class<? extends PhaseListener> 
phaseListenerClass)
+        {
+            for (PhaseListener pl : phaseListeners)
+            {
+                if (pl.getClass().equals(phaseListenerClass))
+                    return; // already there
+            }
+            // Not found: Create and Append
+            log.info("Adding Lifecycle PhaseListener {}", 
phaseListenerClass.getName());
+            PhaseListener listener = 
ClassUtils.newInstance(phaseListenerClass);
+            // Add to bean storage
+            beanStorage.injectBean(listener);
+            // Add to lifecycle
+            lifecycle.addPhaseListener(listener);
+            // refresh
+            // this.phaseListeners = lifecycle.getPhaseListeners();
+        }
+    }
+
+    /**
+     * ConfigTypeList
+     * @author doebele
+     */
+    protected static class ConfigTypeList
+    {
+        private static final String CRLF = "\r\n";
+        private static final String TAB = "\t";
+        private final StringBuilder b;
+        public ConfigTypeList(String listName)
+        {
+            this.b = new StringBuilder(200);
+            b.append(listName);
+            b.append(":");
+            b.append(CRLF);
+        }
+        public void addItem(Object item, Object... more)
+        {
+            b.append(TAB);
+            b.append(toString(item));
+            for (int i=0; i<more.length; i++)
+            {
+                b.append(TAB);
+                b.append(toString(more[i]));
+            }
+            b.append(CRLF);
+        }
+        protected String toString(Object o)
+        {
+            if (o instanceof Class<?>)
+                return ((Class<?>)o).getName();
+            if (o instanceof Enum<?>)
+                return ((Enum<?>)o).name();
+            return String.valueOf(o);
+        }
+        @Override
+        public String toString()
+        {
+           return this.b.toString();
+        }
+    }
+
+}
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebAppStartupListener.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebAppStartupListener.java
index accccf4d..f6e06923 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebAppStartupListener.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebAppStartupListener.java
@@ -36,6 +36,24 @@ import org.slf4j.LoggerFactory;
 public class WebAppStartupListener implements SystemEventListener
 {
     private static final Logger log = 
LoggerFactory.getLogger(WebAppStartupListener.class);
+    
+    private final Class<? extends FacesConfiguration> facesConfigClass;
+
+    /**
+     * Default Constructor with no initialization
+     */
+    public WebAppStartupListener()
+    {
+        this.facesConfigClass = null;
+    }
+
+    /**
+     * Default Constructor with additional configuration
+     */
+    public WebAppStartupListener(Class<? extends FacesConfiguration> 
facesConfigClass)
+    {
+        this.facesConfigClass = facesConfigClass;
+    }
 
     @Override
     public boolean isListenerForSource(Object source)
@@ -51,8 +69,11 @@ public class WebAppStartupListener implements 
SystemEventListener
         if (event instanceof PostConstructApplicationEvent)
         {
             FacesContext startupContext = FacesContext.getCurrentInstance();
-            // detect implementation
+            // Detect implementation
             FacesImplementation facesImplementation = 
detectFacesImplementation();
+            // Init Configuration
+            initFacesConfiguration(startupContext, facesImplementation);
+            // Create Application
             Object app = 
facesImplementation.getManagedBean(WebApplication.APPLICATION_BEAN_NAME, 
startupContext);
             if (!(app instanceof WebApplication))
                 throw new AbortProcessingException("Error: Application is not 
a "+WebApplication.class.getName()+" instance. Please create a 
ApplicationFactory!");
@@ -99,5 +120,18 @@ public class WebAppStartupListener implements 
SystemEventListener
         log.error("JSF-Implementation missing or unknown. Please make sure 
either Apache MyFaces or Sun Mojarra implementation is provided");
         throw new UnsupportedOperationException(); 
     }
+
+    /**
+     * Allows to programmatically extend the faces configuration
+     * @param impl
+     */
+    protected void initFacesConfiguration(FacesContext startupContext, 
FacesImplementation impl)
+    {
+        // Init FacesExtentions
+        if (facesConfigClass!=null) {
+            log.info("Initializing FacesExtentions");
+            FacesConfiguration.initialize(facesConfigClass, startupContext, 
impl);
+        }
+    }
     
 }
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
index 5ab31b26..986a12df 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
@@ -465,7 +465,7 @@ public abstract class WebApplication
      * @param db the database for which to obtain a connection
      * @return the connection
      */
-    protected synchronized Connection getConnection(DBDatabase db)
+    protected Connection getConnection(DBDatabase db)
     {
         // Get From Pool
         try
@@ -488,7 +488,7 @@ public abstract class WebApplication
      * @param commit flag whether to commit changes
      * @param dbrm the rollback manager
      */
-    protected synchronized void releaseConnection(Connection conn, boolean 
commit, DBRollbackManager dbrm)
+    protected void releaseConnection(Connection conn, boolean commit, 
DBRollbackManager dbrm)
     {
         try
         {   // check
diff --git a/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java 
b/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java
index 4e38dce4..66f63ef7 100644
--- a/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java
@@ -29,6 +29,7 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.net.URISyntaxException;
 
 import org.apache.commons.beanutils.ConstructorUtils;
 import org.apache.empire.exceptions.EmpireException;
@@ -321,29 +322,56 @@ public final class ClassUtils
     }
 
     /**
-     * Retrieve a field value using reflection 
+     * Modifies a private field value using reflection 
      * @param clazz the class of the object
      * @param object the object or null if static fields are to be changed
      * @param property the field name
      * @param value the field value
      */
-    public static synchronized void setPrivateFieldValue(Class<?> clazz, 
Object object, String property, Object value)
+    public static void setPrivateFieldValue(Class<?> clazz, Object object, 
String property, Object value)
     {
+        Field field = null;
+        boolean accessible = true; 
         try
-        {
-            Field field = clazz.getDeclaredField(property);
-            field.setAccessible(true);
-            // Object val = field.get(object);
+        {   // Find field
+            field = clazz.getDeclaredField(property);
+            accessible = field.isAccessible();
+            if (accessible==false)
+                field.setAccessible(true);
+            // Set value 
             field.set(object, value);
-            field.setAccessible(false);
         }
-        catch (Exception e)
+        catch (NoSuchFieldException e)
+        {   // try superclass
+            clazz = clazz.getSuperclass();
+            if (clazz!=null && !clazz.equals(java.lang.Object.class))
+                setPrivateFieldValue(clazz, object, property, value);
+            // not found
+            log.error("Field \""+property+"\" not found on class 
"+clazz.getName());
+            throw new InternalException(e);
+        }
+        catch (SecurityException | IllegalArgumentException | 
IllegalAccessException e)
         {   // Access Error
-            log.error("Unable to modify private field '"+property+"* on class 
'"+clazz.getName()+"'", e);
+            log.error("Failed to modify private field \""+property+"\" on 
class "+clazz.getName(), e);
             throw new InternalException(e);
+        } finally {
+            // restore accessible
+            if (field!=null && accessible==false)
+                field.setAccessible(false);
         }
     }
 
+    /**
+     * Modifies a private field value using reflection 
+     * @param object the object or null if static fields are to be changed
+     * @param property the field name
+     * @param value the field value
+     */
+    public static void setPrivateFieldValue(Object object, String property, 
Object value)
+    {
+        setPrivateFieldValue(object.getClass(), object, property, value);
+    }
+    
     /**
      * Creates a new Object instance
      * @param typeClass the class of the object to instantiate
@@ -616,4 +644,53 @@ public final class ClassUtils
         return invokeSimpleMethod(object.getClass(), object, methodName, true);
     }
 
+    /**
+     * Returns the JAR name that contains the implementation of a specific 
class
+     * @param clazz the class 
+     * @return the JAR File Name
+     */
+    public static String getImplemenationJarName(Class<?> clazz)
+    {
+        String implJar;
+        try
+        {   // detect
+            implJar = clazz.getProtectionDomain()
+                    .getCodeSource()
+                    .getLocation()
+                    .toURI()
+                    .getPath();
+            // return JAR name
+            return implJar.substring(implJar.lastIndexOf('/')+1);
+        }
+        catch (URISyntaxException e)
+        {
+            log.error("getImplemenationJarName failed.", e);
+            return "[URISyntaxException]";
+        }
+        catch (NullPointerException e)
+        {
+            log.error("getImplemenationJarName failed.", e);
+            return "[NullPointerException]";
+        }
+    }
+
+    /**
+     * Returns the JAR name that contains the implementation of a specific 
class
+     * @param className the class Name of the class 
+     * @return the JAR File Name or "[ClassNotFoundException]" if the class is 
not available
+     */
+    public static String getImplemenationJarName(String className)
+    {
+        try
+        {   // Find the Class for the given name
+            Class<?> clazz = Class.forName(className);
+            return getImplemenationJarName(clazz);
+        }
+        catch (ClassNotFoundException e)
+        {
+            log.info("Class \"{}\" not found", className);
+            return "[ClassNotFoundException]";
+        }
+    }
+    
 }
diff --git 
a/empire-db/src/main/java/org/apache/empire/exceptions/MiscellaneousErrorException.java
 b/empire-db/src/main/java/org/apache/empire/exceptions/MiscErrorException.java
similarity index 83%
rename from 
empire-db/src/main/java/org/apache/empire/exceptions/MiscellaneousErrorException.java
rename to 
empire-db/src/main/java/org/apache/empire/exceptions/MiscErrorException.java
index 2d3e0d77..7402a20b 100644
--- 
a/empire-db/src/main/java/org/apache/empire/exceptions/MiscellaneousErrorException.java
+++ 
b/empire-db/src/main/java/org/apache/empire/exceptions/MiscErrorException.java
@@ -20,14 +20,12 @@ package org.apache.empire.exceptions;
 
 /**
  * MiscellaneousErrorException
- * @deprecated use UnspecifiedErrorException
  */
-@Deprecated
-public final class MiscellaneousErrorException extends 
UnspecifiedErrorException
+public final class MiscErrorException extends UnspecifiedErrorException
 {
     private static final long serialVersionUID = 1L;
 
-    public MiscellaneousErrorException(String errorMessage)
+    public MiscErrorException(String errorMessage)
     {
         super(errorMessage);
     }

Reply via email to