001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.connector.deployment.jsr88;
018    
019    import java.io.InputStream;
020    import java.io.IOException;
021    import java.io.OutputStream;
022    import java.util.Map;
023    import java.util.HashMap;
024    import java.util.List;
025    import java.util.ArrayList;
026    import java.util.Iterator;
027    import java.util.Arrays;
028    import javax.enterprise.deploy.model.DDBeanRoot;
029    import javax.enterprise.deploy.model.DDBean;
030    import javax.enterprise.deploy.spi.DConfigBean;
031    import javax.enterprise.deploy.spi.exceptions.ConfigurationException;
032    import org.apache.geronimo.deployment.plugin.DConfigBeanRootSupport;
033    import org.apache.geronimo.xbeans.geronimo.GerConnectorDocument;
034    import org.apache.geronimo.xbeans.geronimo.GerAdminobjectInstanceType;
035    import org.apache.geronimo.xbeans.geronimo.GerConnectiondefinitionInstanceType;
036    import org.apache.geronimo.xbeans.geronimo.GerResourceadapterInstanceType;
037    import org.apache.geronimo.xbeans.geronimo.GerConfigPropertySettingType;
038    import org.apache.xmlbeans.XmlObject;
039    import org.apache.xmlbeans.XmlException;
040    import org.apache.xmlbeans.SchemaTypeLoader;
041    import org.apache.xmlbeans.XmlBeans;
042    import org.apache.xmlbeans.XmlCursor;
043    
044    /**
045     * Represents "/" in a Geronimo Connector deployment plan (geronimo-ra.xml).
046     * The only function here is to navigate to an appropriate "Connector"
047     * DConfigBean.
048     *
049     * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
050     */
051    public class Connector15DCBRoot extends DConfigBeanRootSupport {
052        // This may be overcomplicated -- if we don't refer to J2EE types in our schemas
053        // then we should only need to use the GerConnectorDocument loader
054        static final SchemaTypeLoader SCHEMA_TYPE_LOADER = XmlBeans.typeLoaderUnion(new SchemaTypeLoader[] {
055            XmlBeans.typeLoaderForClassLoader(org.apache.geronimo.xbeans.j2ee.String.class.getClassLoader()),
056            XmlBeans.typeLoaderForClassLoader(GerConnectorDocument.class.getClassLoader())
057        });
058    
059        private ConnectorDCB connector;
060    
061        public Connector15DCBRoot(DDBeanRoot ddBean) {
062            super(ddBean, null);
063            setXmlObject(loadDefaultData(ddBean));
064        }
065    
066        private XmlObject loadDefaultData(DDBeanRoot root) {
067            InputStream in = root.getDeployableObject().getEntry("META-INF/geronimo-ra.xml");
068            if(in == null) {
069                GerConnectorDocument doc = GerConnectorDocument.Factory.newInstance();
070                DDBean[] list = root.getChildBean("connector");
071                if(list.length > 0) {
072                    connector = new ConnectorDCB(list[0], doc.addNewConnector());
073                }
074                return doc;
075            } else {
076                try {
077                    GerConnectorDocument result =  GerConnectorDocument.Factory.parse(in);
078                    in.close();
079                    DDBean[] list = root.getChildBean("connector");
080                    if(list.length > 0) {
081                        connector = new ConnectorDCB(list[0], result.getConnector());
082                    }
083                    return result;
084                } catch (XmlException e) {
085                    throw new RuntimeException("Unable to load default Geronimo RA data", e);
086                } catch (IOException e) {
087                    throw new RuntimeException("Unable to load default Geronimo RA data", e);
088                }
089            }
090        }
091    
092        GerConnectorDocument getConnectorDocument() {
093            return (GerConnectorDocument) getXmlObject();
094        }
095    
096        public String[] getXpaths() {
097            return getXPathsForJ2ee_1_4(new String[][]{{"connector",},});
098        }
099    
100        public DConfigBean getDConfigBean(DDBean bean) throws ConfigurationException {
101            if (getXpaths()[0].equals(bean.getXpath())) { // "connector"
102                return connector;
103            } else {
104                throw new ConfigurationException("No DConfigBean matching DDBean "+bean.getXpath());
105            }
106        }
107    
108        protected SchemaTypeLoader getSchemaTypeLoader() {
109            return SCHEMA_TYPE_LOADER;
110        }
111    
112        /**
113         * When loaded, reset the cached "connector" child
114         */
115        public void fromXML(InputStream inputStream) throws XmlException, IOException {
116            DDBean ddb = connector.getDDBean();
117            super.fromXML(inputStream);
118            if(getConnectorDocument().getConnector() != null) {
119                connector = new ConnectorDCB(ddb, getConnectorDocument().getConnector());
120            } else {
121                connector = new ConnectorDCB(ddb, getConnectorDocument().addNewConnector());
122            }
123            //todo: fire some kind of notification for the DDBeans to catch?
124        }
125    
126        /**
127         * A little trickery -- on a save event, temporarily remove any config-property-setting
128         * elements with a null value, and then immediately replace them again.  This is because
129         * we don't want to write them out as null, but we also want to keep the objects in
130         * sync 1:1 with the config params declared in the J2EE deployment descriptor.
131         */
132        public void toXML(OutputStream outputStream) throws IOException {
133            List parents = new ArrayList();
134            clearNulls(parents);
135            try {
136                super.toXML(outputStream);
137            } finally {
138                for (int i = 0; i < parents.size(); i++) {
139                    Object parent = parents.get(i);
140                    ConfigHolder instance = (ConfigHolder) parent;
141                    instance.reconfigure();
142                }
143            }
144        }
145    
146        private void clearNulls(List parents) {
147            ResourceAdapter[] adapters = connector.getResourceAdapter();
148            for (int i = 0; i < adapters.length; i++) {
149                ResourceAdapter adapter = adapters[i];
150                if(adapter.getResourceAdapterInstance() != null) {
151                    parents.add(adapter.getResourceAdapterInstance());
152                    adapter.getResourceAdapterInstance().clearNullSettings();
153                }
154                ConnectionDefinition defs[] = adapter.getConnectionDefinition();
155                for (int j = 0; j < defs.length; j++) {
156                    ConnectionDefinition def = defs[j];
157                    ConnectionDefinitionInstance instances[] = def.getConnectionInstances();
158                    for (int k = 0; k < instances.length; k++) {
159                        ConnectionDefinitionInstance instance = instances[k];
160                        parents.add(instance);
161                        instance.clearNullSettings();
162                    }
163                }
164            }
165            try {
166                DDBean[] adminDDBs = connector.getDDBean().getChildBean(connector.getXpaths()[0]);
167                if(adminDDBs == null) adminDDBs = new DDBean[0];
168                for (int i = 0; i < adminDDBs.length; i++) {
169                    DDBean ddb = adminDDBs[i];
170                    AdminObjectDCB dcb = (AdminObjectDCB) connector.getDConfigBean(ddb);
171                    AdminObjectInstance[] instances = dcb.getAdminObjectInstance();
172                    for (int j = 0; j < instances.length; j++) {
173                        AdminObjectInstance instance = instances[j];
174                        parents.add(instance);
175                        instance.clearNullSettings();
176                    }
177                }
178            } catch (ConfigurationException e) {
179                e.printStackTrace();
180            }
181        }
182    }