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                service.run();
176                // the service instance is returned as an opaque object.
177                return service;
178            } catch (TransientServiceException e) {
179                throw new ConfigException("Error starting transient name service", e);
180            }
181        }
182    
183        /**
184         * Destroy a name service instance created by a
185         * prior call to createNameService().
186         *
187         * @param ns     The opaque name service object returned from a
188         *               prior call to createNameService().
189         */
190        public void destroyNameService(Object ns) {
191            // The name service instance handles its own shutdown.
192            ((TransientNameService)ns).destroy();
193        }
194    
195        /**
196         * Create an ORB instance using the configured argument
197         * and property bundles.
198         *
199         * @param name   The String name of the configuration GBean used to
200         *               create this ORB.
201         * @param config The GBean configuration object required by the
202         *               SocketFactory instance.
203         * @param args   The String arguments passed to ORB.init().
204         * @param props  The property bundle passed to ORB.init().
205         *
206         * @return An ORB constructed from the provided args and properties.
207         */
208        private ORB createORB(String name, ORBConfiguration config, String[] args, Properties props) {
209            return ORB.init(args, props);
210        }
211    
212        /**
213         * Translate a CORBABean configuration into an
214         * array of arguments used to configure the ORB
215         * instance.
216         *
217         * @param server The CORBABean we're creating an ORB instance for.
218         *
219         * @return A String{} array containing the initialization
220         *         arguments.
221         * @exception ConfigException if configuration cannot be interpreted
222         */
223        private String[] translateToArgs(CORBABean server) throws ConfigException {
224            ArrayList<String> list = new ArrayList<String>();
225    //TODO GERONIMO-2687, I don't think it makes sense to associate a default principal with  a tss config, but if we need it
226            //here's the disfunctional code.
227    //        TSSConfig config = server.getTssConfig();
228    
229            // if the TSSConfig includes principal information, we need to add argument values
230            // for this information.
231    //        DefaultPrincipal principal = config.getDefaultPrincipal();
232    //        if (principal != null) {
233    //            if (principal instanceof DefaultRealmPrincipal) {
234    //                DefaultRealmPrincipal realmPrincipal = (DefaultRealmPrincipal) principal;
235    //                list.add("default-realm-principal::" + realmPrincipal.getRealm() + ":" + realmPrincipal.getDomain() + ":"
236    //                         + realmPrincipal.getPrincipal().getClassName() + ":" + realmPrincipal.getPrincipal().getPrincipalName());
237    //            } else if (principal instanceof DefaultDomainPrincipal) {
238    //                DefaultDomainPrincipal domainPrincipal = (DefaultDomainPrincipal) principal;
239    //                list.add("default-domain-principal::" + domainPrincipal.getDomain() + ":"
240    //                         + domainPrincipal.getPrincipal().getClassName() + ":" + domainPrincipal.getPrincipal().getPrincipalName());
241    //            } else {
242    //                list.add("default-principal::" + principal.getPrincipal().getClassName() + ":" + principal.getPrincipal().getPrincipalName());
243    //            }
244    //        }
245    
246            // enable the connection plugin
247            enableSocketFactory(server.getURI(), list);
248    
249            NameService nameService = server.getNameService();
250            // if we have a name service to enable as an initial ref, add it to the init processing.
251            if (nameService != null) {
252                list.add("-ORBInitRef");
253                list.add("NameService=" + nameService.getURI());
254            }
255    
256            if (log.isDebugEnabled()) {
257                for (String configArg : list) {
258                    log.debug(configArg);
259                }
260            }
261    
262            return list.toArray(new String[list.size()]);
263        }
264    
265        private Properties translateToProps(CORBABean server) throws ConfigException {
266            Properties result = new Properties();
267    
268            result.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
269            result.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
270            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.transaction.TransactionInitializer", "");
271            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.security.SecurityInitializer", "");
272            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.yoko.ORBInitializer", "");
273            // don't specify the port if we're allowing this to default.
274            if (server.getPort() > 0) {
275                result.put("yoko.orb.oa.endpoint", "iiop --host " + server.getHost() + " --port " + server.getPort());
276            }
277            else {
278                result.put("yoko.orb.oa.endpoint", "iiop --host " + server.getHost());
279            }
280            
281            // this gives us a connection we can use to retrieve the ORB configuration in the 
282            // interceptors. 
283            result.put("yoko.orb.id", server.getURI()); 
284    
285            // check the tss config for a transport mech definition.  If we have one, then 
286            // the port information will be passed in that config, and the port in the IIOP profile 
287            // needs to be zero. 
288            TSSConfig config = server.getTssConfig();
289            TSSTransportMechConfig transportMech = config.getTransport_mech();
290            if (transportMech != null) {
291                if (transportMech instanceof TSSSSLTransportConfig) {
292                    result.put("yoko.orb.policy.zero_port", "true");
293                }
294            }
295    
296            if (log.isDebugEnabled()) {
297                log.debug("translateToProps(TSSConfig)");
298                for (Enumeration iter = result.keys(); iter.hasMoreElements();) {
299                    String key = (String) iter.nextElement();
300                    log.debug(key + " = " + result.getProperty(key));
301                }
302            }
303            return result;
304        }
305    
306        /**
307         * Translate a CSSBean configuration into the
308         * argument bundle needed to instantiate the
309         * ORB instance.
310         *
311         * @param client The CSSBean holding the configuration.
312         *
313         * @return A String array to be passed to ORB.init().
314         * @exception ConfigException if configuration cannot be interpreted
315         */
316        private String[] translateToArgs(CSSBean client) throws ConfigException {
317            ArrayList<String> list = new ArrayList<String>();
318    
319            // enable the connection plugin
320            enableSocketFactory(client.getURI(), list);
321    
322            if (log.isDebugEnabled()) {
323                for (String configArg : list) {
324                    log.debug(configArg);
325                }
326            }
327    
328            return list.toArray(new String[list.size()]);
329        }
330    
331        /**
332         * Add arguments to the ORB.init() argument list
333         * required to enable the SocketFactory used for
334         * SSL support.
335         *
336         * @param uri    The URI name of the configuration GBean (either a
337         *               CSSBean or a CORBABean).
338         * @param args configuration arguments to add to
339         */
340        private void enableSocketFactory(String uri, List<String> args) {
341            args.add("-IIOPconnectionHelper");
342            args.add("org.apache.geronimo.yoko.SocketFactory");
343            args.add("-IIOPconnectionHelperArgs");
344            args.add(uri);
345        }
346    
347    
348        /**
349         * Translate a CSSBean configuration into the
350         * property bundle necessary to configure the
351         * ORB instance.
352         *
353         * @param client The CSSBean holding the configuration.
354         *
355         * @return A property bundle that can be passed to ORB.init();
356         * @exception ConfigException if configuration cannot be interpreted
357         */
358        private Properties translateToProps(CSSBean client) throws ConfigException {
359            Properties result = new Properties();
360    
361            result.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
362            result.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
363            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.transaction.TransactionInitializer", "");
364            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.corba.security.SecurityInitializer", "");
365            result.put("org.omg.PortableInterceptor.ORBInitializerClass.org.apache.geronimo.yoko.ORBInitializer", "");
366    
367            // this gives us a connection we can use to retrieve the ORB configuration in the 
368            // interceptors. 
369            result.put("yoko.orb.id", client.getURI()); 
370    
371            if (log.isDebugEnabled()) {
372                log.debug("translateToProps(CSSConfig)");
373                for (Enumeration iter = result.keys(); iter.hasMoreElements();) {
374                    String key = (String) iter.nextElement();
375                    log.debug(key + " = " + result.getProperty(key));
376                }
377            }
378            return result;
379        }
380    
381    
382        /**
383         * Translate a CSSBean configuration into the
384         * property bundle necessary to configure the
385         * ORB instance.
386         *
387         * @param client The CSSBean holding the configuration.
388         *
389         * @return A property bundle that can be passed to ORB.init();
390         * @exception ConfigException if configuration cannot be interpreted
391         */
392        private Properties translateToNameServiceProps(CSSBean client) throws ConfigException {
393            Properties result = new Properties();
394    
395            result.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB");
396            result.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton");
397    
398            if (log.isDebugEnabled()) {
399                log.debug("translateToNameServiceProps(CSSConfig)");
400                for (Enumeration iter = result.keys(); iter.hasMoreElements();) {
401                    String key = (String) iter.nextElement();
402                    log.debug(key + " = " + result.getProperty(key));
403                }
404            }
405            return result;
406        }
407    }