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.yoko;
018    
019    import java.lang.reflect.Method;
020    import java.util.ArrayList;
021    import java.util.Enumeration;
022    import java.util.List;
023    import java.util.Properties;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.geronimo.corba.CORBABean;
028    import org.apache.geronimo.corba.CSSBean;
029    import org.apache.geronimo.corba.NameService;
030    import org.apache.geronimo.corba.ORBConfiguration;
031    import org.apache.geronimo.corba.security.config.ConfigAdapter;
032    import org.apache.geronimo.corba.security.config.ConfigException;
033    import org.apache.geronimo.corba.security.config.tss.TSSConfig;
034    import org.apache.geronimo.corba.security.config.tss.TSSSSLTransportConfig;
035    import org.apache.geronimo.corba.security.config.tss.TSSTransportMechConfig;
036    import org.apache.geronimo.gbean.GBeanLifecycle;
037    import org.apache.yoko.orb.CosNaming.tnaming.TransientNameService;
038    import org.apache.yoko.orb.CosNaming.tnaming.TransientServiceException;
039    import org.apache.yoko.orb.OB.ZERO_PORT_POLICY_ID;
040    import org.omg.CORBA.Any;
041    import org.omg.CORBA.ORB;
042    import org.omg.CORBA.Policy;
043    
044    
045    /**
046     * A ConfigAdapter instance for the Apache Yoko
047     * CORBA support.
048     * @version $Revision: 497125 $ $Date: 2007-01-17 10:51:30 -0800 (Wed, 17 Jan 2007) $
049     */
050    public class ORBConfigAdapter implements GBeanLifecycle, ConfigAdapter {
051    
052        private final Log log = LogFactory.getLog(ORBConfigAdapter.class);
053    
054        public ORBConfigAdapter() {
055        }
056    
057        /**
058         * Start the config adapter GBean.  This is basically
059         * an opportunity to set any system properties
060         * required to make the ORB hook ups.  In particular,
061         * this makes the ORB hookups for the RMI over IIOP
062         * support.
063         *
064         * @exception Exception
065         */
066        public void doStart() throws Exception {
067            // define the default ORB for ORB.init();
068            System.setProperty("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
069            System.setProperty("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
070    
071            // redirect the RMI implementation to use the Yoko ORB.
072            System.setProperty("javax.rmi.CORBA.PortableRemoteObjectClass", "org.apache.yoko.rmi.impl.PortableRemoteObjectImpl");
073            System.setProperty("javax.rmi.CORBA.StubClass", "org.apache.yoko.rmi.impl.StubImpl");
074            // this hooks the util class and allows us to override certain functions
075            System.setProperty("javax.rmi.CORBA.UtilClass", "org.apache.geronimo.corba.util.UtilDelegateImpl");
076            // this tells the openejb UtilDelegateImpl which implementation to delegate non-overridden
077            // operations to.
078            System.setProperty("org.apache.geronimo.corba.UtilDelegateClass", "org.apache.yoko.rmi.impl.UtilImpl");
079            // this allows us to hook RMI stub invocation/serialization events. 
080            System.setProperty("org.apache.yoko.rmi.RMIStubInitializerClass", "org.apache.geronimo.yoko.RMIStubHandlerFactory");
081    
082            // ok, now we have a potential classloading problem because of where our util delegates are located.
083            // by forcing these classes to load now using our class loader, we can ensure things are properly initialized
084            Class clazz = this.getClass().getClassLoader().loadClass("javax.rmi.PortableRemoteObject");
085            Method m = clazz.getMethod("narrow", Object.class, Class.class);
086            m.invoke(null, new Object(), Object.class);
087    
088    
089            log.debug("Started  Yoko ORBConfigAdapter");
090        }
091    
092        public void doStop() throws Exception {
093            // nothing really required here.
094            log.debug("Stopped Yoko ORBConfigAdapter");
095        }
096    
097        public void doFail() {
098            // nothing much to do.
099            log.warn("Failed Yoko ORBConfigAdapter");
100        }
101    
102        /**
103         * Create an ORB for a CORBABean server context.
104         *
105         * @param server The CORBABean that owns this ORB's configuration.
106         *
107         * @return An ORB instance configured for the CORBABean.
108         * @exception ConfigException
109         */
110        public ORB createServerORB(CORBABean server)  throws ConfigException {
111            ORB orb = createORB(server.getURI(), server, translateToArgs(server), translateToProps(server));
112    
113            // check the tss config for a transport mech definition.  If we have one, then 
114            // the port information will be passed in that config, and the port in the IIOP profile 
115            // needs to be zero. 
116            TSSConfig config = server.getTssConfig();
117            TSSTransportMechConfig transportMech = config.getTransport_mech();
118            if (transportMech != null) {
119                if (transportMech instanceof TSSSSLTransportConfig) {
120                    Any any = orb.create_any();
121                    any.insert_boolean(true);
122    
123                    try {
124                        Policy portPolicy = orb.create_policy(ZERO_PORT_POLICY_ID.value, any);
125                        Policy[] overrides = new Policy [] { portPolicy };
126                        server.setPolicyOverrides(overrides);
127                    } catch (org.omg.CORBA.PolicyError e) {
128                        // shouldn't happen, but we'll let things continue with no policy set. 
129                    }
130    
131                }
132            }
133    
134            return orb;
135        }
136    
137        /**
138         * Create an ORB for a CSSBean client context.
139         *
140         * @param client The configured CSSBean used for access.
141         *
142         * @return An ORB instance configured for this client access.
143         * @exception ConfigException
144         */
145        public ORB createClientORB(CSSBean client)  throws ConfigException {
146            return createORB(client.getURI(), client, translateToArgs(client), translateToProps(client));
147        }
148    
149        /**
150         * Create an ORB for a CSSBean name service client context.
151         *
152         * @param client The configured CSSBean used for access.
153         *
154         * @return An ORB instance configured for this client access.
155         * @exception ConfigException
156         */
157        public ORB createNameServiceClientORB(CSSBean client)  throws ConfigException {
158            return createORB(client.getURI(), client, translateToArgs(client), translateToNameServiceProps(client));
159        }
160    
161        /**
162         * Create a transient name service instance using the
163         * specified host name and port.
164         *
165         * @param host   The String host name.
166         * @param port   The port number of the listener.
167         *
168         * @return An opaque object that represents the name service.
169         * @exception ConfigException
170         */
171        public Object createNameService(String host, int port) throws ConfigException {
172            try {
173                // create a name service using the supplied host and publish under the name "NameService"
174                TransientNameService service = new TransientNameService(host, port, "NameService") {
175                    public void run() throws TransientServiceException {
176                        // Create an ORB object
177                        java.util.Properties props = new Properties();
178                        props.putAll(System.getProperties());
179    
180                        props.put("org.omg.CORBA.ORBServerId", "1000000" ) ;
181                        props.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
182                        props.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
183                        props.put("yoko.orb.oa.endpoint", "iiop --bind " + host  + " --host " + host + " --port " + port );
184    
185                        createdOrb = ORB.init((String[])null, props) ;
186    
187                        // now initialize the service
188                        initialize(createdOrb);
189                    }
190                };
191                service.run();
192                log.debug("Creating ORB endpoint with host=" + host + ", port=" + port);            
193                // the service instance is returned as an opaque object.
194                return service;
195            } catch (TransientServiceException e) {
196                throw new ConfigException("Error starting transient name service on port " + port, e);
197            }
198        }
199    
200        /**
201         * Destroy a name service instance created by a
202         * prior call to createNameService().
203         *
204         * @param ns     The opaque name service object returned from a
205         *               prior call to createNameService().
206         */
207        public void destroyNameService(Object ns) {
208            // The name service instance handles its own shutdown.
209            ((TransientNameService)ns).destroy();
210        }
211    
212        /**
213         * Create an ORB instance using the configured argument
214         * and property bundles.
215         *
216         * @param name   The String name of the configuration GBean used to
217         *               create this ORB.
218         * @param config The GBean configuration object required by the
219         *               SocketFactory instance.
220         * @param args   The String arguments passed to ORB.init().
221         * @param props  The property bundle passed to ORB.init().
222         *
223         * @return An ORB constructed from the provided args and properties.
224         */
225        private ORB createORB(String name, ORBConfiguration config, String[] args, Properties props) {
226            return ORB.init(args, props);
227        }
228    
229        /**
230         * Translate a CORBABean configuration into an
231         * array of arguments used to configure the ORB
232         * instance.
233         *
234         * @param server The CORBABean we're creating an ORB instance for.
235         *
236         * @return A String{} array containing the initialization
237         *         arguments.
238         * @exception ConfigException if configuration cannot be interpreted
239         */
240        private String[] translateToArgs(CORBABean server) throws ConfigException {
241            ArrayList<String> list = new ArrayList<String>();
242    //TODO GERONIMO-2687, I don't think it makes sense to associate a default principal with  a tss config, but if we need it
243            //here's the disfunctional code.
244    //        TSSConfig config = server.getTssConfig();
245    
246            // if the TSSConfig includes principal information, we need to add argument values
247            // for this information.
248    //        DefaultPrincipal principal = config.getDefaultPrincipal();
249    //        if (principal != null) {
250    //            if (principal instanceof DefaultRealmPrincipal) {
251    //                DefaultRealmPrincipal realmPrincipal = (DefaultRealmPrincipal) principal;
252    //                list.add("default-realm-principal::" + realmPrincipal.getRealm() + ":" + realmPrincipal.getDomain() + ":"
253    //                         + realmPrincipal.getPrincipal().getClassName() + ":" + realmPrincipal.getPrincipal().getPrincipalName());
254    //            } else if (principal instanceof DefaultDomainPrincipal) {
255    //                DefaultDomainPrincipal domainPrincipal = (DefaultDomainPrincipal) principal;
256    //                list.add("default-domain-principal::" + domainPrincipal.getDomain() + ":"
257    //                         + domainPrincipal.getPrincipal().getClassName() + ":" + domainPrincipal.getPrincipal().getPrincipalName());
258    //            } else {
259    //                list.add("default-principal::" + principal.getPrincipal().getClassName() + ":" + principal.getPrincipal().getPrincipalName());
260    //            }
261    //        }
262    
263            // enable the connection plugin
264            enableSocketFactory(server.getURI(), list);
265    
266            NameService nameService = server.getNameService();
267            // if we have a name service to enable as an initial ref, add it to the init processing.
268            if (nameService != null) {
269                list.add("-ORBInitRef");
270                list.add("NameService=" + nameService.getURI());
271            }
272    
273            if (log.isDebugEnabled()) {
274                for (String configArg : list) {
275                    log.debug(configArg);
276                }
277            }
278    
279            return list.toArray(new String[list.size()]);
280        }
281    
282        private Properties translateToProps(CORBABean server) throws ConfigException {
283            Properties result = new Properties();
284    
285            result.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
286            result.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
287            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.transaction.TransactionInitializer", "");
288            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.security.SecurityInitializer", "");
289            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.yoko.ORBInitializer", "");
290            // don't specify the port if we're allowing this to default.
291            if (server.getPort() > 0) {
292                result.put("yoko.orb.oa.endpoint", "iiop --bind " + server.getHost() + " --host " + server.getHost() + " --port " + server.getPort());
293            }
294            else {
295                result.put("yoko.orb.oa.endpoint", "iiop --bind " + server.getHost()+ " --host " + server.getHost());
296            }
297            
298            // this gives us a connection we can use to retrieve the ORB configuration in the 
299            // interceptors. 
300            result.put("yoko.orb.id", server.getURI()); 
301    
302            // check the tss config for a transport mech definition.  If we have one, then 
303            // the port information will be passed in that config, and the port in the IIOP profile 
304            // needs to be zero. 
305            TSSConfig config = server.getTssConfig();
306            TSSTransportMechConfig transportMech = config.getTransport_mech();
307            if (transportMech != null) {
308                if (transportMech instanceof TSSSSLTransportConfig) {
309                    result.put("yoko.orb.policy.zero_port", "true");
310                }
311            }
312    
313            if (log.isDebugEnabled()) {
314                log.debug("translateToProps(TSSConfig)");
315                for (Enumeration iter = result.keys(); iter.hasMoreElements();) {
316                    String key = (String) iter.nextElement();
317                    log.debug(key + " = " + result.getProperty(key));
318                }
319            }
320            return result;
321        }
322    
323        /**
324         * Translate a CSSBean configuration into the
325         * argument bundle needed to instantiate the
326         * ORB instance.
327         *
328         * @param client The CSSBean holding the configuration.
329         *
330         * @return A String array to be passed to ORB.init().
331         * @exception ConfigException if configuration cannot be interpreted
332         */
333        private String[] translateToArgs(CSSBean client) throws ConfigException {
334            ArrayList<String> list = new ArrayList<String>();
335    
336            // enable the connection plugin
337            enableSocketFactory(client.getURI(), list);
338    
339            if (log.isDebugEnabled()) {
340                for (String configArg : list) {
341                    log.debug(configArg);
342                }
343            }
344    
345            return list.toArray(new String[list.size()]);
346        }
347    
348        /**
349         * Add arguments to the ORB.init() argument list
350         * required to enable the SocketFactory used for
351         * SSL support.
352         *
353         * @param uri    The URI name of the configuration GBean (either a
354         *               CSSBean or a CORBABean).
355         * @param args configuration arguments to add to
356         */
357        private void enableSocketFactory(String uri, List<String> args) {
358            args.add("-IIOPconnectionHelper");
359            args.add("org.apache.geronimo.yoko.SocketFactory");
360            args.add("-IIOPconnectionHelperArgs");
361            args.add(uri);
362        }
363    
364    
365        /**
366         * Translate a CSSBean configuration into the
367         * property bundle necessary to configure the
368         * ORB instance.
369         *
370         * @param client The CSSBean holding the configuration.
371         *
372         * @return A property bundle that can be passed to ORB.init();
373         * @exception ConfigException if configuration cannot be interpreted
374         */
375        private Properties translateToProps(CSSBean client) throws ConfigException {
376            Properties result = new Properties();
377    
378            result.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
379            result.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
380            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.transaction.TransactionInitializer", "");
381            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.security.SecurityInitializer", "");
382            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.yoko.ORBInitializer", "");
383    
384            // this gives us a connection we can use to retrieve the ORB configuration in the 
385            // interceptors. 
386            result.put("yoko.orb.id", client.getURI()); 
387    
388            if (log.isDebugEnabled()) {
389                log.debug("translateToProps(CSSConfig)");
390                for (Enumeration iter = result.keys(); iter.hasMoreElements();) {
391                    String key = (String) iter.nextElement();
392                    log.debug(key + " = " + result.getProperty(key));
393                }
394            }
395            return result;
396        }
397    
398    
399        /**
400         * Translate a CSSBean configuration into the
401         * property bundle necessary to configure the
402         * ORB instance.
403         *
404         * @param client The CSSBean holding the configuration.
405         *
406         * @return A property bundle that can be passed to ORB.init();
407         * @exception ConfigException if configuration cannot be interpreted
408         */
409        private Properties translateToNameServiceProps(CSSBean client) throws ConfigException {
410            Properties result = new Properties();
411    
412            result.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
413            result.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
414    
415            if (log.isDebugEnabled()) {
416                log.debug("translateToNameServiceProps(CSSConfig)");
417                for (Enumeration iter = result.keys(); iter.hasMoreElements();) {
418                    String key = (String) iter.nextElement();
419                    log.debug(key + " = " + result.getProperty(key));
420                }
421            }
422            return result;
423        }
424    }