001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.q2.qbean;
020
021import org.jdom2.Element;
022import org.jpos.core.ConfigurationException;
023import org.jpos.q2.QBeanSupport;
024import org.jpos.q2.QFactory;
025import org.jpos.util.NameRegistrar;
026
027import java.util.*;
028
029/**
030 * QBean that instantiates and registers arbitrary beans declared in its
031 * persist element, exposing them through {@link #getBean(String)} and the
032 * JMX {@link QBeanFactoryMBean} interface.
033 */
034@SuppressWarnings("unchecked")
035public class QBeanFactory extends QBeanSupport implements QBeanFactoryMBean {
036    /** Default constructor; no instance state to initialise. */
037    public QBeanFactory() {}
038  
039    private static Map beanMap = new WeakHashMap();
040    private Map privateList; // list of beans in the config file
041
042    public void initService() throws Exception {
043        Element e = getPersist();
044        privateList = new HashMap();
045        List beans = e.getChildren("bean");
046        for (Object bean1 : beans) {
047            Element bean = (Element) bean1;
048            String id = bean.getAttributeValue("id");
049            privateList.put(id, bean);
050        }
051
052    }
053
054    public void start() {
055        super.start();
056        NameRegistrar.register("QBeanFactory." + getName(), this);
057    }
058
059    public void stop() {
060        super.stop();
061        NameRegistrar.unregister("QBeanFactory." + getName());
062    }
063    // Support methods for bean life cycle
064    public void startService() {
065        Iterator keys = privateList.keySet().iterator();
066        while (keys.hasNext()) {
067            Element bean = (Element) privateList.get(keys.next());
068            String id = bean.getAttributeValue("id");
069            String lazy = bean.getAttributeValue("lazy");
070            // Load the bean only when lazy="false". default value true
071            if (lazy != null && lazy.equalsIgnoreCase("false")) {
072                getBean(id);
073            }
074        }
075    }
076
077    public void stopService() {
078        Iterator keys = privateList.keySet().iterator();
079        while (keys.hasNext()) {
080            Element bean = (Element) privateList.get(keys.next());
081            String id = bean.getAttributeValue("id");// id and key are same
082            Object beanInstance=beanMap.remove(id);
083            String stopMethod = bean.getAttributeValue("stop-method");
084            if(beanInstance!=null && stopMethod!=null){
085                try{
086                    QFactory.invoke(beanInstance, stopMethod, null);
087                }catch(Exception e){
088                    log.warn(e);
089                }
090            }
091        }
092    }
093
094    public Object getBean(String id) {
095
096        // Hack to support a global ref bean across multiple
097        // deployment files. We may need to support lazy loading here but now
098        // not supported
099        Element bean = (Element) privateList.get(id);
100        if (bean == null) {
101            return beanMap.get(id);
102        }
103        // Need to create a new instance when singleton="false"
104        // It is true by default
105        String singleton = bean.getAttributeValue("singleton");
106       try{ 
107        if(singleton != null && singleton.equals("false")){// create new instance every time
108            return newBean(bean,false);
109        }else{
110            return newBean(bean,true); 
111        }
112        }catch(Exception e){
113            log.fatal(e);
114            return null;
115        }
116       
117    }
118    private Object newBean(Element bean,boolean useCache) throws ConfigurationException{
119        String id = bean.getAttributeValue("id");
120        
121        if(useCache && beanMap.containsKey(id)){
122            return beanMap.get(id);
123        }
124        
125        String className = bean.getAttributeValue("class");
126        Object beanInstance = getFactory().newInstance(className);
127        List propertyList = bean.getChildren("property");
128        for (Object aPropertyList : propertyList) {
129            Element propertyElement = (Element) aPropertyList;
130            String pName = propertyElement.getAttributeValue("name");
131            String pValue = propertyElement.getAttributeValue("value");
132            String pRef = propertyElement.getAttributeValue("ref");
133            String methodName = "set"
134                    + Character.toUpperCase(pName.charAt(0))
135                    + pName.substring(1);
136            if (pValue == null) {
137                QFactory.invoke(beanInstance, methodName, getBean(pRef));
138            } else {
139                QFactory.invoke(beanInstance, methodName, pValue);
140            }
141        }
142        String startMethod = bean.getAttributeValue("start-method");
143        if(startMethod!=null){
144            QFactory.invoke(beanInstance, startMethod, null);
145        }
146        if(useCache)//indication for a singleton 
147          beanMap.put(id, beanInstance);   
148        // Return the bean instance
149        return beanInstance;
150    }
151
152}