Package org.wso2.carbon.ui.deployment

Source Code of org.wso2.carbon.ui.deployment.UIBundleDeployer

/*
* Copyright 2005-2007 WSO2, Inc. (http://wso2.com)
*
* Licensed 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.wso2.carbon.ui.deployment;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.equinox.http.helper.ContextPathServletAdaptor;
import org.eclipse.equinox.http.helper.FilterServletAdaptor;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.util.tracker.ServiceTracker;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.CarbonException;
import org.wso2.carbon.ui.BundleResourcePathRegistry;
import org.wso2.carbon.ui.BundleBasedUIResourceProvider;
import org.wso2.carbon.ui.util.UIResourceProvider;
import org.wso2.carbon.ui.deployment.beans.CarbonUIDefinitions;
import org.wso2.carbon.ui.deployment.beans.Component;
import org.wso2.carbon.ui.deployment.beans.CustomUIDefenitions;
import org.wso2.carbon.ui.deployment.beans.FileUploadExecutorConfig;
import org.wso2.carbon.ui.internal.CarbonUIServiceComponent;
import org.wso2.carbon.ui.transports.fileupload.FileUploadExecutorManager;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.net.URL;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

public class UIBundleDeployer implements BundleListener {

    private static Log log = LogFactory.getLog(UIBundleDeployer.class);
    private String bundleResourcePath = "/web";
    private BundleContext bundleContext;
    private HttpContext httpContext;
    private ServiceTracker fileUploadExecManagerTracker;
    private BundleBasedUIResourceProvider bundleBasedUIResourceProvider =
            new BundleBasedUIResourceProvider(bundleResourcePath);

    public UIResourceProvider getBundleBasedUIResourcePrvider() {
        return bundleBasedUIResourceProvider;
    }

    public void deploy(BundleContext bundleContext, HttpContext context) {
        this.bundleContext = bundleContext;
        this.httpContext = context;

        fileUploadExecManagerTracker = new ServiceTracker(bundleContext,
                FileUploadExecutorManager.class.getName(), null);
        fileUploadExecManagerTracker.open();

        //When Carbon starts up with existing set of bundles which contain component.xmls,
        //the bundleChanged() method does not get called. So calling processComponentXML()
        //method here seems to be the only solution.
        //TODO fork a new thread to do this task since this needs some processing time.
        for (Bundle bundle : bundleContext.getBundles()) {
            if ((bundle.getState() & (Bundle.UNINSTALLED | Bundle.INSTALLED)) == 0) {
                try {
                    processUIBundle(bundle, CarbonConstants.ADD_UI_COMPONENT);
                } catch (Exception e) {
                    log.error("Error occured when processing ui bundle " + bundle.getSymbolicName(), e);
                }
            }
        }

        try {
            bundleContext.addServiceListener(new ServletServiceListener(),
                    "(objectClass=" + Servlet.class.getName() + ")");
        } catch (InvalidSyntaxException e) {
            log.error(e);
        }
    }

    public void bundleChanged(BundleEvent event) {
        Bundle bundle = event.getBundle();
        try {
            switch (event.getType()) {
                //TODO need to fix here.
                case BundleEvent.RESOLVED:
                    processUIBundle(bundle, CarbonConstants.ADD_UI_COMPONENT);
                    break;

                case BundleEvent.UNRESOLVED:
//                    processUIBundle(bundle, CarbonConstants.REMOVE_UI_COMPONENT);
                    break;
            }
        } catch (Exception e) {
            log.error("Error occured when processing component xml in bundle " + bundle.getSymbolicName(), e);
        }
    }

    /**
     * 1)Search for the UIBundle header
     * 2)Check for UI bundle fragments - for backward compatibility
     *
     * @param bundle
     * @param action
     * @throws CarbonException
     */
    private void processUIBundle(Bundle bundle, String action) throws CarbonException {
        Dictionary headers = bundle.getHeaders();

        String value = (String) headers.get("Carbon-Component");
        if (value != null && "UIBundle".equals(value)) {
            this.bundleBasedUIResourceProvider.addBundleResourcePaths(bundle);
            processComponentXML(bundle, action);
        } else if ((getHostBundle(bundle)) != null) {
            processComponentXML(bundle, action);
        }
    }

    /**
     * Read component.xml(if any) and invoke suitable actions
     *
     * @param bundle
     * @param action - used to determine if a menu item should be added or removed from UI. Value for action
     *               is determined by the bundle's lifecycle method(RESOLVED,...,etc).
     */
    private void processComponentXML(Bundle bundle, String action) throws CarbonException {
        if (bundleContext.getBundle() == bundle) {
            return;
        }

        Component component = ComponentBuilder.build(bundle, bundleContext);
        if (component == null) {
            return;
        } else {
            ServiceReference reference = bundleContext.getServiceReference(CarbonUIDefinitions.class.getName());
            CarbonUIDefinitions carbonUIDefinitions = null;
            if (reference != null) {
                carbonUIDefinitions = (CarbonUIDefinitions) bundleContext.getService(reference);
            }
            if (carbonUIDefinitions != null) {
                if (log.isDebugEnabled()) {
                    log.debug("Found carbonUIDefinitions in OSGi context");
                }
                carbonUIDefinitions.setMenuDefinitions(component.getMenus(), action);
                carbonUIDefinitions.setServletDefinitions(component.getServlets(), action);
                carbonUIDefinitions.addUnauthenticatedUrls(component.getUnauthenticatedUrlList());
                carbonUIDefinitions.addSkipTilesUrls(component.getSkipTilesUrlList());
                carbonUIDefinitions.addHttpUrls(component.getSkipHttpsUrlList());
                carbonUIDefinitions.addContexts(component.getContextsList());
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("CarbonUIDefinitions is NULL. Registering new...");
                }
                carbonUIDefinitions = new CarbonUIDefinitions();
                carbonUIDefinitions.setMenuDefinitions(component.getMenus(), action);
                carbonUIDefinitions.setServletDefinitions(component.getServlets(), action);
                carbonUIDefinitions.addUnauthenticatedUrls(component.getUnauthenticatedUrlList());
                carbonUIDefinitions.addSkipTilesUrls(component.getSkipTilesUrlList());
                carbonUIDefinitions.addHttpUrls(component.getSkipHttpsUrlList());
                carbonUIDefinitions.addContexts(component.getContextsList());
                bundleContext.registerService(CarbonUIDefinitions.class.getName(), carbonUIDefinitions, null);
            }
        }

        //processing servlet definitions
        if (component != null
                && component.getServlets() != null
                && component.getServlets().length > 0) {
            HttpService httpService;
            try {
                httpService = CarbonUIServiceComponent.getHttpService();
            } catch (Exception e) {
                throw new CarbonException("An instance of HttpService is not available");
            }
            org.wso2.carbon.ui.deployment.beans.Servlet[] servletDefinitions = component.getServlets();
            for (int a = 0; a < servletDefinitions.length; a++) {
                org.wso2.carbon.ui.deployment.beans.Servlet servlet = servletDefinitions[a];
                if (log.isTraceEnabled()) {
                    log.trace("Registering sevlet : " + servlet);
                }
                try {
                    Class clazz = Class.forName(servlet.getServletClass());
                    //TODO : allow servlet parameters to be passed
                    Dictionary params = new Hashtable();
                    httpService.registerServlet(servlet.getUrlPatten(),
                            (Servlet) clazz.newInstance(), params,
                            httpContext);

                } catch (ClassNotFoundException e) {
                    log.error("Servlet class : " + servlet.getServletClass() + " not found.", e);
                } catch (ServletException e) {
                    log.error("Problem registering Servlet class : " + servlet.getServletClass() + ".", e);
                } catch (NamespaceException e) {
                    log.error("Problem registering Servlet class : " + servlet.getServletClass() + ".", e);
                } catch (InstantiationException e) {
                    log.error("Problem registering Servlet class : " + servlet.getServletClass() + ".", e);
                } catch (IllegalAccessException e) {
                    log.error("Problem registering Servlet class : " + servlet.getServletClass() + ".", e);
                }
            }

        }

        // processing the custom UI definitions required by Registry
        if (component != null) {

            ServiceReference reference =
                    bundleContext.getServiceReference(CustomUIDefenitions.class.getName());
            CustomUIDefenitions customUIDefenitions = null;
            if (reference != null) {
                customUIDefenitions = (CustomUIDefenitions) bundleContext.getService(reference);
            }

            if (customUIDefenitions == null) {
                String msg = "Custom UI defenitions service is not available.";
                log.error(msg);
                throw new CarbonException(msg);
            }

            Iterator<String> viewMediaTypes = component.getCustomViewUIMap().keySet().iterator();
            while (viewMediaTypes.hasNext()) {
                String mediaType = viewMediaTypes.next();
                String uiPath = component.getCustomViewUIMap().get(mediaType);
                if (customUIDefenitions.getCustomViewUI(mediaType) == null) {
                    customUIDefenitions.addCustomViewUI(mediaType, uiPath);
                    if (log.isDebugEnabled()) {
                        log.debug("Registered the custom view UI media type: " + mediaType + ", UI path: " + uiPath);
                    }
                } else {
                    String msg = "Custom view UI is already registered for media type: " + mediaType +
                            ". Custom UI with media type: " + mediaType + " and UI path: " +
                            uiPath + " will not be registered.";
                    log.error(msg);
                }
            }

            Iterator<String> addMediaTypes = component.getCustomAddUIMap().keySet().iterator();
            while (addMediaTypes.hasNext()) {
                String mediaType = addMediaTypes.next();
                String uiPath = component.getCustomAddUIMap().get(mediaType);
                if (customUIDefenitions.getCustomAddUI(mediaType) == null) {
                    customUIDefenitions.addCustomAddUI(mediaType, uiPath);
                    if (log.isDebugEnabled()) {
                        log.debug("Registered the custom add UI media type: " + mediaType + ", UI path: " + uiPath);
                    }
                } else {
                    String msg = "Custom add UI is already registered for media type: " + mediaType +
                            ". Custom UI with media type: " + mediaType + " and UI path: " +
                            uiPath + " will not be registered.";
                    log.error(msg);
                }
            }
        }

        //This functionality can be moved to a new method
        if (component.getFileUploadExecutorConfigs() != null
                && component.getFileUploadExecutorConfigs().length > 0) {
            FileUploadExecutorManager executorManager = (FileUploadExecutorManager) fileUploadExecManagerTracker.getService();
            if (executorManager == null) {
                log.error("FileUploadExecutorManager service is not available");
                return;
            }
            FileUploadExecutorConfig[] executorConfigs = component.getFileUploadExecutorConfigs();
            for (FileUploadExecutorConfig executorConfig : executorConfigs) {
                String[] mappingActions = executorConfig.getMappingActionList();
                for (String mappingAction : mappingActions) {
                    if (CarbonConstants.ADD_UI_COMPONENT.equals(action)) {
                        executorManager.addExecutor(mappingAction, executorConfig.getFUploadExecClass());
                    } else if (CarbonConstants.REMOVE_UI_COMPONENT.equals(action)) {
                        executorManager.removeExecutor(mappingAction);
                    }
                }
            }
        }
    }

    /**
     * return the Host Bundle of the provided bundle, only if the provided bundle is a fragment
     *
     * @param bundle to be checked for the validity
     * @return boolean value
     */
    private Bundle getHostBundle(Bundle bundle) {
        PackageAdmin packageAdmin;
        try {
            packageAdmin = CarbonUIServiceComponent.getPackageAdmin();
        } catch (Exception e) {
            return null;
        }
        //Check for a fragment host
        if (packageAdmin.getBundleType(bundle) != PackageAdmin.BUNDLE_TYPE_FRAGMENT)
            return null;

        //If the host bundle is org.wso2.carbon.ui, the proceed, otherwise return
        long uiBundleID = bundleContext.getBundle().getBundleId();
        Bundle[] hostBundles = packageAdmin.getHosts(bundle);
        if (hostBundles != null) {
            for (Bundle hostBundle : hostBundles) {
                if (hostBundle.getBundleId() == uiBundleID) {
                    return hostBundle;
                }
            }
        }
        return null;
    }

//    private void addBundleResourcePaths(Bundle bundle) {
//        Enumeration entries = bundle.findEntries("web", "*", false);
//        while (entries != null && entries.hasMoreElements()) {
//            URL url = (URL) entries.nextElement();
//            String path = url.getPath();
//            if (path.endsWith("/")) {
//                String bundleResourcePath = path.substring("/web/".length(), path.length() - 1);
//                resourcePathRegistry.addBundleResourcePath(bundleResourcePath, bundle);
//            }
//        }
//
//    }

    public void registerServlet(Servlet servlet, String urlPattern, Dictionary params,
                                Dictionary servletAttrs, int event, javax.servlet.Filter associatedFilter) throws CarbonException {

        HttpService httpService;
        try {
            httpService = CarbonUIServiceComponent.getHttpService();
        } catch (Exception e) {
            throw new CarbonException("An instance of HttpService is not available");
        }
        try {
            if (event == ServiceEvent.REGISTERED) {
                Servlet adaptedJspServlet = new ContextPathServletAdaptor(servlet, urlPattern);
                if (associatedFilter == null) {
                    httpService.registerServlet(urlPattern, adaptedJspServlet, params, httpContext);
                } else {
                    httpService.registerServlet(urlPattern,
                            new FilterServletAdaptor(associatedFilter, null, adaptedJspServlet), params, httpContext);
                }
                if (servletAttrs != null) {
                    for (Enumeration enm = servletAttrs.keys(); enm.hasMoreElements();) {
                        String key = (String) enm.nextElement();
                        adaptedJspServlet.getServletConfig().getServletContext().setAttribute(key, servletAttrs.get(key));
                    }
                }
            } else if (event == ServiceEvent.UNREGISTERING) {
                httpService.unregister(urlPattern);
            }

        } catch (Exception e) {
            throw new CarbonException("Error occurred while registering servlet", e);
        }
    }

    public class ServletServiceListener implements ServiceListener {

        public ServletServiceListener() {
            try {
                ServiceReference[] servletSRs = bundleContext.getServiceReferences(null,
                        "(objectClass=" + Servlet.class.getName() + ")");

                if (servletSRs != null) {
                    for (ServiceReference sr : servletSRs) {
                        registerServletFromSR(sr, ServiceEvent.REGISTERED);
                    }
                }
            } catch (Exception e) {
                log.error("Failed to obtain registerd services. Invalid filter Syntax.", e);
            }
        }

        public void serviceChanged(ServiceEvent event) {
            if (event.getType() == ServiceEvent.REGISTERED) {
                registerServletFromSR(event.getServiceReference(), event.getType());
            }
        }

        public void registerServletFromSR(ServiceReference sr, int event) {
            Servlet servlet = (Servlet) bundleContext.getService(sr);
            if (servlet == null) {
                log.error("Servlet instance cannot be null");
                return;
            }

            Object urlPatternObj = sr.getProperty(CarbonConstants.SERVLET_URL_PATTERN);
            if (urlPatternObj == null || !(urlPatternObj instanceof String) || urlPatternObj.equals("")) {
                log.error("URL pattern should not be null");
                return;
            }
            String urlPattern = (String) urlPatternObj;

            Object paramsObj = sr.getProperty(CarbonConstants.SERVLET_PARAMS);
            if (paramsObj != null && !(paramsObj instanceof Dictionary)) {
                log.error("Servlet params instances should be type of Dictionary");
                return;
            }
            Dictionary params = (Dictionary) paramsObj;

            Object attributesObj = sr.getProperty(CarbonConstants.SERVLET_ATTRIBUTES);
            if (attributesObj != null && !(attributesObj instanceof Dictionary)) {
                log.error("Servlet attributes instances should be type of Dictionary");
                return;
            }
            Dictionary attributes = (Dictionary) attributesObj;

            Object associatedFilterObj = sr.getProperty(CarbonConstants.ASSOCIATED_FILTER);

            // use the qualified name for the Filter as it will by default conflicted with the OSGI class
            javax.servlet.Filter associatedFilter = null;
            if (associatedFilterObj != null) {
                associatedFilter = (javax.servlet.Filter) associatedFilterObj;
            }

            try {
                registerServlet(servlet, urlPattern, params, attributes, event, associatedFilter);
            } catch (CarbonException e) {
                log.error(e);
            }
        }
    }
}
TOP

Related Classes of org.wso2.carbon.ui.deployment.UIBundleDeployer

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.