Package org.apache.geronimo.client

Source Code of org.apache.geronimo.client.AppClientContainer

/**
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.geronimo.client;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import org.apache.geronimo.gbean.AbstractName;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.j2ee.annotation.Holder;
import org.apache.geronimo.j2ee.annotation.Injection;
import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.security.Callers;
import org.apache.geronimo.security.ContextManager;
import org.apache.geronimo.security.credentialstore.CredentialStore;
import org.apache.geronimo.security.deploy.SubjectInfo;
import org.apache.xbean.recipe.ObjectRecipe;
import org.apache.xbean.recipe.Option;
import org.apache.xbean.recipe.StaticRecipe;

/**
* @version $Rev: 698441 $ $Date: 2008-09-24 00:10:08 -0700 (Wed, 24 Sep 2008) $
*/
public final class AppClientContainer implements GBeanLifecycle {
    private static final Class[] MAIN_ARGS = {String[].class};
   
    private LoginContext loginContext;

    private final String mainClassName;
    private final AppClientPlugin jndiContext;
    private final AbstractName appClientModuleName;
    private final String realmName;
    private final String callbackHandlerClass;
    private final Subject defaultSubject;
    private final Method mainMethod;
    private final ClassLoader classLoader;
    private final Kernel kernel;
    private final Holder holder;
    private CallbackHandler callbackHandler;

    public AppClientContainer(String mainClassName,
            AbstractName appClientModuleName,
            String realmName,
            String callbackHandlerClassName,
            SubjectInfo defaultSubject,
            Holder holder,
            AppClientPlugin jndiContext,
            CredentialStore credentialStore,
            ClassLoader classLoader,
            Kernel kernel
    ) throws Exception {
        // set the geronimo identity resolver hook for openejb
        System.setProperty("openejb.client.identityResolver", "geronimo");

        this.mainClassName = mainClassName;
        this.appClientModuleName = appClientModuleName;
        if ((realmName == null) != (callbackHandlerClassName == null)) {
            throw new IllegalArgumentException("You must supply both realmName and callbackHandlerClass or neither");
        }
        this.realmName = realmName;
        this.callbackHandlerClass = callbackHandlerClassName;

        if (defaultSubject != null) {
            this.defaultSubject = credentialStore.getSubject(defaultSubject.getRealm(), defaultSubject.getId());
        } else {
            this.defaultSubject = null;
        }
        this.holder = holder == null ? Holder.EMPTY : holder;
        this.classLoader = classLoader;
        this.kernel = kernel;
        this.jndiContext = jndiContext;

        try {
            Class mainClass = classLoader.loadClass(mainClassName);
            mainMethod = mainClass.getMethod("main", MAIN_ARGS);
        } catch (ClassNotFoundException e) {
            throw new AppClientInitializationException("Unable to load Main-Class " + mainClassName, e);
        } catch (NoSuchMethodException e) {
            throw new AppClientInitializationException("Main-Class " + mainClassName + " does not have a main method", e);
        }
    }

    public AbstractName getAppClientModuleName() {
        return appClientModuleName;
    }

    public String getMainClassName() {
        return mainClassName;
    }

    public void main(final String[] args) throws Exception {
        //TODO reorganize this so it makes more sense.  maybe use an interceptor stack.
        //TODO track resource ref shared and app managed security
        Thread thread = Thread.currentThread();

        ClassLoader oldClassLoader = thread.getContextClassLoader();
        Callers oldCallers = ContextManager.getCallers();
        Subject clientSubject = defaultSubject;
        try {
            thread.setContextClassLoader(classLoader);
            jndiContext.startClient(appClientModuleName, kernel, classLoader);
            Context componentContext = jndiContext.getJndiContext();

            if (callbackHandlerClass != null) {
                callbackHandler = (CallbackHandler) holder.newInstance(callbackHandlerClass, classLoader, componentContext);
                loginContext = ContextManager.login(realmName, callbackHandler);
                clientSubject = loginContext.getSubject();
            }
            ContextManager.setCallers(clientSubject, clientSubject);
            Class mainClass = classLoader.loadClass(mainClassName);
            ObjectRecipe objectRecipe = new ObjectRecipe(mainClass);
            objectRecipe.allow(Option.FIELD_INJECTION);
            objectRecipe.allow(Option.PRIVATE_PROPERTIES);
            objectRecipe.allow(Option.STATIC_PROPERTIES);
            List<Injection> injections = new ArrayList<Injection>();
            while (mainClass != null && mainClass != Object.class) {
                List<Injection> perClass = holder.getInjections(mainClass.getName());
                if (perClass != null) {
                    injections.addAll(perClass);
                }
                mainClass = mainClass.getSuperclass();
            }
            if (injections != null) {
                List<NamingException> problems = new ArrayList<NamingException>();
                for (Injection injection : injections) {
                    try {
                        String jndiName = injection.getJndiName();
                        //our componentContext is attached to jndi at "java:comp" so we remove that when looking stuff up in it
                        Object object = componentContext.lookup("env/" + jndiName);
                        if (object instanceof String) {
                            String string = (String) object;
                            // Pass it in raw so it could be potentially converted to
                            // another data type by an xbean-reflect property editor
                            objectRecipe.setProperty(injection.getTargetName(), string);
                        } else {
                            objectRecipe.setProperty(injection.getTargetName(), new StaticRecipe(object));
                        }
                    } catch (NamingException e) {
                        problems.add(e);
                    }
                }
                if (!problems.isEmpty()) {
                    throw new Exception("Some objects to be injected were not found in jndi: " + problems);
                }
            }
            Class clazz = objectRecipe.setStaticProperties();
            if (holder.getPostConstruct() != null) {
                Holder.apply(null, clazz, holder.getPostConstruct());
            }

            if (clientSubject == null) {
                mainMethod.invoke(null, new Object[]{args});
            } else {
                Subject.doAs(clientSubject, new PrivilegedAction() {
                    public Object run() {
                        try {
                            mainMethod.invoke(null, new Object[]{args});
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        } catch (InvocationTargetException e) {
                            throw new RuntimeException(e);
                        }
                        return null;
                    }
                });
            }
        } catch (InvocationTargetException e) {
            Throwable cause = e.getCause();
            if (cause instanceof Exception) {
                throw (Exception) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new Error(e);
        } finally {
            //How can this work??
            thread.setContextClassLoader(oldClassLoader);
            ContextManager.popCallers(oldCallers);
        }
    }

    public void doStart() throws Exception {
    }

    public void doStop() throws Exception {
        if (callbackHandler != null) {
            holder.destroyInstance(callbackHandler);
        }
        if (loginContext != null) {
            ContextManager.logout(loginContext);
        }
        jndiContext.stopClient(appClientModuleName);
    }

    public void doFail() {
        try {
            doStop();
        } catch (Exception e) {
            //ignore
        }
    }


    public static final GBeanInfo GBEAN_INFO;

    static {
        GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(AppClientContainer.class, NameFactory.APP_CLIENT);


        infoFactory.addAttribute("mainClassName", String.class, true);
        infoFactory.addAttribute("appClientModuleName", AbstractName.class, true);
        infoFactory.addAttribute("realmName", String.class, true);
        infoFactory.addAttribute("callbackHandlerClassName", String.class, true);
        infoFactory.addAttribute("defaultSubject", SubjectInfo.class, true);
        infoFactory.addAttribute("holder", Holder.class, true);

        infoFactory.addReference("JNDIContext", AppClientPlugin.class, GBeanInfoBuilder.DEFAULT_J2EE_TYPE);
        infoFactory.addReference("CredentialStore", CredentialStore.class, GBeanInfoBuilder.DEFAULT_J2EE_TYPE);

        infoFactory.addAttribute("classLoader", ClassLoader.class, false);
        infoFactory.addAttribute("kernel", Kernel.class, false);


        infoFactory.setConstructor(new String[]{"mainClassName",
                "appClientModuleName",
                "realmName",
                "callbackHandlerClassName",
                "defaultSubject",
                "holder",
                "JNDIContext",
                "CredentialStore",
                "classLoader",
                "kernel"
        });

        GBEAN_INFO = infoFactory.getBeanInfo();
    }

    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }

}
TOP

Related Classes of org.apache.geronimo.client.AppClientContainer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.