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.util.ArrayList;
020    import java.util.Arrays;
021    import java.util.Collections;
022    import java.util.HashSet;
023    import java.util.Iterator;
024    import java.util.LinkedHashMap;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Set;
028    import javax.enterprise.deploy.model.DDBean;
029    import javax.enterprise.deploy.model.XpathEvent;
030    import javax.enterprise.deploy.model.XpathListener;
031    import javax.enterprise.deploy.spi.DConfigBean;
032    import javax.enterprise.deploy.spi.exceptions.ConfigurationException;
033    import org.apache.geronimo.deployment.plugin.DConfigBeanSupport;
034    import org.apache.geronimo.deployment.service.jsr88.EnvironmentData;
035    import org.apache.geronimo.xbeans.geronimo.GerAdminobjectInstanceType;
036    import org.apache.geronimo.xbeans.geronimo.GerAdminobjectType;
037    import org.apache.geronimo.xbeans.geronimo.GerConnectorType;
038    import org.apache.geronimo.xbeans.geronimo.GerResourceadapterType;
039    import org.apache.xmlbeans.SchemaTypeLoader;
040    import org.apache.xmlbeans.XmlCursor;
041    
042    /**
043     * Represents /connector in a Geronimo Connector deployment plan.
044     * Corresponds to /connector in the J2EE deployment plan.
045     *
046     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
047     */
048    public class ConnectorDCB extends DConfigBeanSupport {
049        private DDBean resourceAdapterDDBean;
050        private ResourceAdapter[] resourceAdapter = new ResourceAdapter[0];
051        private AdminObjectDCB[] adminobjects = new AdminObjectDCB[0];
052        private EnvironmentData environment;
053    
054        public ConnectorDCB(DDBean connectorDDBean, final GerConnectorType connector) {
055            super(connectorDDBean, connector);
056            DDBean[] list = connectorDDBean.getChildBean("resourceadapter");
057            if(list.length > 0) {
058                resourceAdapterDDBean = list[0];
059            }
060            //todo: do something if resourceAdapterDDBean is null
061            loadExistingData(connector);
062    
063            // Make sure we're told if /connector/resourceadapter is replaced!
064            connectorDDBean.addXpathListener("resourceadapter", new XpathListener() {
065                public void fireXpathEvent(XpathEvent event) {
066                    if(event.isRemoveEvent()) {
067                        resourceAdapterDDBean = null; //todo: all our info was just invalidated
068                    } else if(event.isAddEvent()) {
069                        resourceAdapterDDBean = event.getBean(); //todo: reload defaults from DDBean
070                    } else {
071                        System.out.println("Detected change to J2EE DD /connector/resourceadapter property "+event.getChangeEvent().getPropertyName());
072                    }
073                }
074            });
075        }
076    
077        public String[] getXpaths() {
078            return getXPathsForJ2ee_1_4(new String[][]{{"resourceadapter","adminobject",},});
079        }
080    
081        public DConfigBean getDConfigBean(DDBean bean) throws ConfigurationException {
082            if (getXpaths()[0].equals(bean.getXpath())) { // "adminobject"
083                String aoInterface = bean.getText("adminobject-interface")[0];
084                String aoClass = bean.getText("adminobject-class")[0];
085                // Check whether we've seen this one before
086                for(int i=0; i<adminobjects.length; i++) {
087                    if(adminobjects[i].getAdminObjectClass().equals(aoClass) &&
088                       adminobjects[i].getAdminObjectInterface().equals(aoInterface)) {
089                        return adminobjects[i];
090                    }
091                }
092                // Haven't seen it; create a new DConfigBean
093                GerAdminobjectType ao = getConnector().addNewAdminobject();
094                AdminObjectDCB dcb = new AdminObjectDCB(bean, ao);
095                AdminObjectDCB[] list = new AdminObjectDCB[adminobjects.length+1];
096                System.arraycopy(adminobjects, 0, list, 0, adminobjects.length);
097                list[adminobjects.length] = dcb;
098                return dcb;
099            } else {
100                throw new ConfigurationException("No DConfigBean matching DDBean "+bean.getXpath());
101            }
102        }
103    
104        private void loadExistingData(GerConnectorType connector) {
105            //todo: Handle the import children
106            //todo: Handle the hidden-classes children
107            //todo: Handle the non-overridable-classes children
108            // Handle the dependency children
109    //        ArtifactType[] deps = connector.getDependencyArray();
110    //        if(deps != null && deps.length > 0) {
111    //            dependency = new Artifact[deps.length];
112    //            for (int i = 0; i < deps.length; i++) {
113    //                dependency[i] = new Artifact(deps[i]);
114    //            }
115    //        }
116            // Handle the resource adapter children
117            GerResourceadapterType[] adapters = connector.getResourceadapterArray();
118            if(adapters == null || adapters.length == 0) {
119                // Make sure there's at least one connector/resourceadapter element
120                if(resourceAdapterDDBean != null) {
121                    resourceAdapter = new ResourceAdapter[1];
122                    resourceAdapter[0] = new ResourceAdapter(resourceAdapterDDBean, connector.addNewResourceadapter());
123                }
124            } else {
125                resourceAdapter = new ResourceAdapter[adapters.length];
126                for (int i = 0; i < adapters.length; i++) {
127                    GerResourceadapterType adapter = adapters[i];
128                    resourceAdapter[i] = new ResourceAdapter(resourceAdapterDDBean, adapter);
129                }
130            }
131            // Handle the AdminObject children
132            GerAdminobjectType[] admins = connector.getAdminobjectArray();
133            DDBean[] data = getDDBean().getChildBean(getXpaths()[0]);
134            List ddBeans = data == null ? Collections.EMPTY_LIST : new ArrayList(Arrays.asList(data)); // resourceadapter/adminobject
135    
136            Map dcbs = new LinkedHashMap();
137            if(admins == null) {
138                adminobjects = new AdminObjectDCB[0];
139            } else {
140                // Match up each Geronimo adminobject with a ra.xml adminobject and create DConfigBeans accordingly
141                for (int i = 0; i < admins.length; i++) {
142                    GerAdminobjectType admin = admins[i];
143                    String aoClass = admin.getAdminobjectClass();
144                    String aoIface = admin.getAdminobjectInterface();
145                    AdminObjectDCB dcb = (AdminObjectDCB) dcbs.get("class "+aoClass+" iface "+aoIface);
146                    if(dcb != null) {
147                        // this is a second Geronimo adminobject block of the same type; there will not be a matching DDBean any more
148                        // merge the adminobject-instance entries instead!!!
149                        if(admin.getAdminobjectInstanceArray().length > 0) {
150                            GerAdminobjectType old = dcb.getAdminObject();
151                            GerAdminobjectInstanceType[] array = admin.getAdminobjectInstanceArray();
152                            int oldCount = dcb.getAdminObjectInstance().length;
153                            for (int j = 0; j < array.length; j++) {
154                                GerAdminobjectInstanceType instance = array[j];
155                                XmlCursor source = instance.newCursor();
156                                XmlCursor dest = old.newCursor();
157                                dest.toEndToken();
158                                if(!source.moveXml(dest)) {
159                                    throw new RuntimeException("Unable to move admin object instance");
160                                }
161                                source.dispose();
162                                dest.dispose();
163                                dcb.addAdminObjectInstance(old.getAdminobjectInstanceArray(oldCount+j));
164                            }
165                        }
166                        continue;
167                    }
168                    DDBean target = null;
169                    for (int j = 0; j < ddBeans.size(); j++) {
170                        DDBean ddBean = (DDBean) ddBeans.get(j);
171                        String ddClass = ddBean.getText("adminobject-class")[0];
172                        String ddIface = ddBean.getText("adminobject-interface")[0];
173                        if(ddClass.equals(aoClass) && ddIface.equals(aoIface)) {
174                            target = ddBean;
175                            ddBeans.remove(j);
176                            break;
177                        }
178                    }
179                    if(target == null) {
180                        System.out.println("Geronimo connector deployment plan has admin object with interface '"+aoIface+"' and class '"+aoClass+"' but the ra.xml does not have a matching adminobject declared.  Deleting this adminobject from the Geronimo plan.");
181                        continue;
182                    }
183                    dcb = new AdminObjectDCB(target, admin);
184                    dcbs.put("class "+aoClass+" iface "+aoIface, dcb);
185                }
186            }
187            // There are some admin object types in ra.xml with no matching instances; create DConfigBeans for those
188            for (int i = 0; i < ddBeans.size(); i++) {
189                DDBean ddBean = (DDBean) ddBeans.get(i);
190                String ddClass = ddBean.getText("adminobject-class")[0];
191                String ddIface = ddBean.getText("adminobject-interface")[0];
192                GerAdminobjectType admin = connector.addNewAdminobject();
193                dcbs.put("class "+ddClass+" iface "+ddIface, new AdminObjectDCB(ddBean, admin));
194            }
195            List adminResults = new ArrayList();
196            for (Iterator it = dcbs.keySet().iterator(); it.hasNext();) {
197                String key = (String) it.next();
198                DConfigBean value = (DConfigBean) dcbs.get(key);
199                adminResults.add(value);
200            }
201            adminobjects = (AdminObjectDCB[]) adminResults.toArray(new AdminObjectDCB[adminResults.size()]);
202    
203            //todo: Handle the GBean children
204        }
205    
206        GerConnectorType getConnector() {
207            return (GerConnectorType) getXmlObject();
208        }
209    
210    
211        // ----------------------- JavaBean Properties for /connector ----------------------
212    
213        //todo: the following child elements
214        // gbean*
215    
216        public EnvironmentData getEnvironment() {
217            return environment;
218        }
219    
220        public void setEnvironment(EnvironmentData environment) {
221            EnvironmentData old = this.environment;
222            this.environment = environment;
223            if((old == null && environment == null) || (old != null&& old == environment)) {
224                return;
225            }
226            if(old != null) {
227                getConnector().unsetEnvironment();
228            }
229            if(environment != null) {
230                environment.configure(getConnector().addNewEnvironment());
231            }
232            pcs.firePropertyChange("environment", old, environment);
233        }
234    
235        public ResourceAdapter[] getResourceAdapter() {
236            return resourceAdapter;
237        }
238    
239        public void setResourceAdapter(ResourceAdapter[] resourceAdapter) {
240            ResourceAdapter[] old = this.resourceAdapter;
241            Set before = new HashSet();
242            for (int i = 0; i < old.length; i++) {
243                before.add(old[i]);
244            }
245            this.resourceAdapter = resourceAdapter;
246            // Handle current or new resource adapters
247            for (int i = 0; i < resourceAdapter.length; i++) {
248                ResourceAdapter adapter = resourceAdapter[i];
249                if(adapter.getResourceAdapter() == null) {
250                    adapter.configure(resourceAdapterDDBean, getConnector().addNewResourceadapter());
251                } else {
252                    before.remove(adapter);
253                }
254            }
255            // Handle removed resource adapters
256            for (Iterator it = before.iterator(); it.hasNext();) {
257                ResourceAdapter adapter = (ResourceAdapter) it.next();
258                GerResourceadapterType all[] = getConnector().getResourceadapterArray();
259                for (int i = 0; i < all.length; i++) {
260                    if(all[i] == adapter) {
261                        getConnector().removeResourceadapter(i);
262                        break;
263                    }
264                }
265            }
266            pcs.firePropertyChange("resourceAdapter", old, resourceAdapter);
267        }
268    
269        public ResourceAdapter getResourceAdapter(int index) {
270            return resourceAdapter[index];
271        }
272    
273        public void setResourceAdapter(int index, ResourceAdapter ra) {
274            ResourceAdapter[] old = this.resourceAdapter;
275            resourceAdapter[index] = ra;
276            if(ra.getResourceAdapter() == null) {
277                ra.configure(resourceAdapterDDBean, getConnector().addNewResourceadapter());
278            }
279            pcs.firePropertyChange("resourceAdapter", old, resourceAdapter);
280        }
281    
282    
283        // ----------------------- End of JavaBean Properties ----------------------
284    
285    
286    
287        protected SchemaTypeLoader getSchemaTypeLoader() {
288            return Connector15DCBRoot.SCHEMA_TYPE_LOADER;
289        }
290    }