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.corba;
018    
019    import java.net.InetAddress;
020    import java.net.InetSocketAddress;
021    import java.net.UnknownHostException;
022    
023    import javax.ejb.spi.HandleDelegate;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.geronimo.gbean.AbstractName;
028    import org.apache.geronimo.gbean.GBeanLifecycle;
029    import org.apache.geronimo.gbean.InvalidConfigurationException; 
030    import org.apache.geronimo.corba.security.ServerPolicy;
031    import org.apache.geronimo.corba.security.ServerPolicyFactory;
032    import org.apache.geronimo.corba.security.config.ConfigAdapter;
033    import org.apache.geronimo.corba.security.config.ssl.SSLConfig;
034    import org.apache.geronimo.corba.security.config.tss.TSSConfig;
035    import org.apache.geronimo.corba.security.config.tss.TSSSSLTransportConfig;
036    import org.apache.geronimo.corba.security.config.tss.TSSTransportMechConfig;
037    import org.apache.geronimo.corba.util.Util;
038    import org.apache.geronimo.openejb.OpenEjbSystem; 
039    import org.omg.CORBA.Any;
040    import org.omg.CORBA.ORB;
041    import org.omg.CORBA.Policy;
042    import org.omg.PortableServer.POA;
043    import org.omg.PortableServer.POAHelper;
044    
045    
046    /**
047     * A CORBABean is a main CORBA server configuration.  The
048     * CORBABean is the hosting ORB to which additional TSSBeans
049     * attach to export EJBs.  The CORBABean may be configured
050     * to use either plain socket listeners or SSL listeners, based
051     * on the bean specification.  All TSSBean objects attached
052     * to this Bean instance will share the same listener
053     * endpoint and transport-level security.
054     * @version $Revision: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
055     */
056    public class CORBABean implements GBeanLifecycle, ORBRef, ORBConfiguration {
057        private final Log log = LogFactory.getLog(CORBABean.class);
058    
059        private final ClassLoader classLoader;
060        private final ConfigAdapter configAdapter;
061        // the initial listener port
062        private int listenerPort;
063        // the host name we expose in IORs
064        private String host;
065        private TSSConfig tssConfig;
066        private SSLConfig sslConfig;
067        private ORB orb;
068        private POA rootPOA;
069        private NameService nameService;
070        private AbstractName abstractName;
071        private OpenEjbSystem ejbSystem; 
072        // ORB-specific policy overrides we need to add to POA policies created by 
073        // child TSSBeans.  
074        private Policy[] policyOverrides = null; 
075    
076        public CORBABean() {
077            this.classLoader = null;
078            this.configAdapter = null;
079            this.sslConfig = null;
080            this.listenerPort = -1;
081            this.host = null;
082            this.abstractName = null;
083            this.policyOverrides = null; 
084            this.ejbSystem = null;
085        }
086    
087        /**
088         * Instantiate a CORBABean instance.
089         *
090         * @param abstractName
091         *               The server-created abstract name for this bean instance.
092         * @param configAdapter
093         *               The ORB ConfigAdapter used to interface with the
094         *               JVM-configured ORB instance.
095         * @param host   The hostname we publish ourselves under.
096         * @param listenerPort
097         *               The initial listener port to use.
098         * @param classLoader
099         *               The ClassLoader used for ORB context class loading.
100         * @param nameService
101         *               The initial name service the created ORB will use
102         *               for object resolution.
103         * @param ssl    The SSL configuration, including the KeystoreManager.
104         *
105         */
106        public CORBABean(AbstractName abstractName, ConfigAdapter configAdapter, String host, int listenerPort, ClassLoader classLoader, NameService nameService, OpenEjbSystem ejbSystem, SSLConfig ssl) {
107            this.abstractName = abstractName;
108            this.classLoader = classLoader;
109            this.configAdapter = configAdapter;
110            sslConfig = ssl;
111            this.nameService = nameService;
112            this.host = host;
113            this.listenerPort = listenerPort;
114            this.policyOverrides = null; 
115            this.ejbSystem = ejbSystem; 
116        }
117    
118        /**
119         * Retrieve the NameService this CORBA server depends upon.
120         *
121         * @return The configured NameService instance.
122         */
123        public NameService getNameService() {
124            return nameService;
125        }
126    
127        /**
128         * Setter attribute for the NameService.
129         *
130         * @param s      The new target name service.
131         */
132        public void setNameService(NameService s) {
133            nameService = s;
134        }
135    
136        /**
137         * Get the optional TSSConfig object specified for this
138         * CORBABean server.
139         *
140         * @return The TSSConfig object (if any).
141         */
142        public TSSConfig getTssConfig() {
143            // if nothing has been explicitly set, ensure we return
144            // a default one.
145            if (tssConfig == null) {
146                tssConfig = new TSSConfig();
147            }
148            return tssConfig;
149        }
150    
151        /**
152         * Set a TSSConfig value for this CORBA instance.
153         *
154         * @param config The required TSSConfig information.
155         */
156        public void setTssConfig(TSSConfig config) {
157            this.tssConfig = config;
158        }
159    
160        /**
161         * Return the SSLConfig used for this ORB instance.
162         * if one has not been configured, this returns
163         * a default configuration.
164         *
165         * @return The SSLConfig object use to manage transport-level
166         *         security.
167         */
168        public SSLConfig getSslConfig() {
169            if (sslConfig == null) {
170                sslConfig = new SSLConfig();
171            }
172            return sslConfig;
173        }
174    
175        /**
176         * Attribute setter for the SSL configuration.
177         *
178         * @param c      The new SSLConfig object used for secure communications.
179         */
180        public void setSslConfing(SSLConfig c) {
181            sslConfig = c;
182        }
183    
184    
185        /**
186         * Return the ORB instance created for this CORBABean.
187         *
188         * @return The ORB instance backing this bean.
189         */
190        public ORB getORB() {
191            return orb;
192        }
193    
194        public HandleDelegate getHandleDelegate() {
195            return new CORBAHandleDelegate();
196        }
197    
198        /**
199         * Get the root POA() instance associated with the ORB.
200         *
201         * @return The rootPOA instance obtained from the ORB.
202         */
203        public POA getRootPOA() {
204            return rootPOA;
205        }
206    
207        /**
208         * Retrieve the listener address (host/port combo) used
209         * by the ORB.
210         *
211         * @return An InetSocketAddress item identifying the end point
212         *         for the ORB.
213         */
214        public InetSocketAddress getListenAddress() {
215            return new InetSocketAddress(host, listenerPort);
216        }
217    
218        /**
219         * Start the ORB associated with this bean instance.
220         *
221         * @exception Exception
222         */
223        public void doStart() throws Exception {
224    
225            ClassLoader savedLoader = Thread.currentThread().getContextClassLoader();
226            try {
227                Thread.currentThread().setContextClassLoader(classLoader);
228    
229                // make sure we've decided how the listener should be configured.
230                resolveListenerAddress();
231                // register this so we can retrieve this in the interceptors 
232                Util.registerORB(getURI(), this); 
233    
234                log.debug("CORBABean " + getURI() + " creating listener on port " + listenerPort);
235                // the config adapter creates the actual ORB instance for us.
236                orb = configAdapter.createServerORB(this);
237    
238                // we set this ORB value into the Util.  The Util ORB is used for a lot of utility things, so
239                // we'll cache the first instance created.
240                Util.setORB(orb);
241                
242                // TSSBeans are going to need our rootPOA instance, so resolve this now.
243                org.omg.CORBA.Object obj = orb.resolve_initial_references("RootPOA");
244                rootPOA = POAHelper.narrow(obj);
245                // if we have an OpenEjbSystem reference, inform the ejb subsystem 
246                // there's now an ORB available for the JNDI context. 
247                if (ejbSystem != null) {
248                    ejbSystem.setORBContext(orb, getHandleDelegate()); 
249                }
250            } catch (NoSuchMethodError e) {
251                log.error("Incorrect level of org.omg.CORBA classes found.\nLikely cause is an incorrect java.endorsed.dirs configuration"); 
252                throw new InvalidConfigurationException("CORBA usage requires Yoko CORBA spec classes in java.endorsed.dirs classpath", e); 
253            } finally {
254                Thread.currentThread().setContextClassLoader(savedLoader);
255            }
256    
257        }
258    
259        public void doStop() throws Exception {
260            orb.destroy();
261            // remove this from the registry 
262            Util.unregisterORB(getURI()); 
263            log.debug("Stopped CORBABean");
264        }
265    
266        public void doFail() {
267            log.warn("Failed CORBABean");
268        }
269    
270        /**
271         * Process the specified host/port information on
272         * both the bean and the TSSConfig to arrive at a
273         * target port.  This must be called prior to creating
274         * the ORB.
275         */
276        private void resolveListenerAddress() {
277            // now provide defaults for anything still needing resolving
278            if (host == null) {
279                try {
280                    host = InetAddress.getLocalHost().getHostName();
281                } catch (UnknownHostException e) {
282                    // just punt an use localhost as an absolute fallback.
283                    host = "localhost";
284                }
285            }
286            
287            // if nothing has been explicitly specified, we use a port value of -1, which
288            // allows the ORB to allocate the address.
289            
290            // if we have a config with a TSSSSLTransportConfig defined, the
291            // host and port from the config override bean-configured values.
292            if (tssConfig != null) {
293                TSSTransportMechConfig transportMech = tssConfig.getTransport_mech();
294                if (transportMech != null) {
295                    if (transportMech instanceof TSSSSLTransportConfig) {
296                        TSSSSLTransportConfig transportConfig = (TSSSSLTransportConfig) transportMech;
297                        transportConfig.setHostname(host); 
298                        transportConfig.setPort((short)listenerPort); 
299                    }
300                }
301            }
302    
303        }
304    
305        /**
306         * Return the retrieval URI for this bean.
307         *
308         * @return The URI for the bean AbstractName;
309         */
310        public String getURI() {
311            return abstractName.toString();
312        }
313    
314        /**
315         * Get the configured listener port.
316         *
317         * @return The configeration port value.
318         */
319        public int getPort() {
320            return listenerPort;
321        }
322    
323        /**
324         * Get the configuration host name.
325         *
326         * @return The configuration host name.  The default is "localhost".
327         */
328        public String getHost() {
329            return host;
330        }
331        
332        /**
333         * Set a set of policy overrides to be used with 
334         * this ORB instance.  These are normally set by 
335         * the ORBConfigAdapter instance when the ORB 
336         * is created. 
337         * 
338         * @param overrides The new override list.
339         */
340        public void setPolicyOverrides(Policy[] overrides) {
341            policyOverrides = overrides; 
342        }
343        
344        /**
345         * Add the policy overrides (if any) to the list 
346         * of policies used to create a POA instance.
347         * 
348         * @param policies The base set of policies.
349         * 
350         * @return A new Policy array with the overrides added.  Returns
351         *         the same array if no overrides are required.
352         */
353        public Policy[] addPolicyOverrides(Policy[] policies) {
354            // just return the same list of no overrides exist 
355            if (policyOverrides == null) {
356                return policies; 
357            }
358            
359            Policy[] newPolicies = new Policy[policies.length + policyOverrides.length]; 
360            
361            System.arraycopy(policies, 0, newPolicies, 0, policies.length); 
362            System.arraycopy(policyOverrides, 0, newPolicies, policies.length, policyOverrides.length); 
363            
364            return newPolicies; 
365        }
366    }