com.haulmont.cuba.web.sys.WebExternalUIComponentsSource.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.web.sys.WebExternalUIComponentsSource.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * 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 com.haulmont.cuba.web.sys;

import com.google.common.collect.ImmutableMap;
import com.haulmont.bali.util.Dom4j;
import com.haulmont.cuba.core.global.Resources;
import com.haulmont.cuba.core.sys.AppContext;
import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.xml.layout.ComponentLoader;
import com.haulmont.cuba.gui.xml.layout.ExternalUIComponentsSource;
import com.haulmont.cuba.gui.xml.layout.LayoutLoaderConfig;
import com.haulmont.cuba.gui.xml.layout.loaders.FrameLoader;
import com.haulmont.cuba.gui.xml.layout.loaders.WindowLoader;
import com.haulmont.cuba.web.App;
import com.haulmont.cuba.web.gui.WebComponentsFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrTokenizer;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;

import javax.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang.StringUtils.trimToEmpty;

/**
 * Class registers external components that are supplied in separate jars or defined in 'cuba-ui-component.xml'
 * descriptor of 'web' module.
 */
@org.springframework.stereotype.Component(ExternalUIComponentsSource.NAME)
public class WebExternalUIComponentsSource implements ExternalUIComponentsSource {

    private static final String WEB_COMPONENTS_CONFIG_XML_PROP = "cuba.web.componentsConfig";

    private final Logger log = LoggerFactory.getLogger(WebExternalUIComponentsSource.class);

    protected static final String WINDOW_LOADER_EL = "windowLoader";
    protected static final String FRAME_LOADER_EL = "frameLoader";
    protected static final String EDITOR_LOADER_EL = "editorLoader";
    protected static final String LOOKUP_LOADER_EL = "lookupLoader";

    protected static final Map<String, Class<? extends FrameLoader>> loaders = ImmutableMap.of(WINDOW_LOADER_EL,
            WindowLoader.class, FRAME_LOADER_EL, FrameLoader.class, EDITOR_LOADER_EL, WindowLoader.Editor.class,
            LOOKUP_LOADER_EL, WindowLoader.Lookup.class);

    @Inject
    protected Resources resources;

    @Inject
    protected WebComponentsFactory webComponentsFactory;

    protected volatile boolean initialized;

    @Override
    public void checkInitialized() {
        if (!initialized) {
            synchronized (this) {
                if (!initialized) {
                    log.debug("Init external UI components");

                    init();
                    initialized = true;
                }
            }
        }
    }

    protected void init() {
        try {
            // register component from app components
            _registerAppComponents();
            //register components from external component jars
            _registerComponents("META-INF/cuba-ui-component.xml");
            //register components from web modules
            _registerComponents("cuba-ui-component.xml");

        } catch (Exception e) {
            log.error("Error on custom UI components registration", e);
        }
    }

    protected void _registerAppComponents() {
        String configName = AppContext.getProperty(WEB_COMPONENTS_CONFIG_XML_PROP);
        StrTokenizer tokenizer = new StrTokenizer(configName);
        for (String location : tokenizer.getTokenArray()) {
            Resource resource = resources.getResource(location);
            if (resource.exists()) {
                InputStream stream = null;
                try {
                    stream = resource.getInputStream();
                    _registerComponent(stream);
                } catch (ClassNotFoundException | IOException e) {
                    throw new RuntimeException(e);
                } finally {
                    IOUtils.closeQuietly(stream);
                }
            } else {
                log.warn("Resource {} not found, ignore it", location);
            }
        }
    }

    protected void _registerComponents(String componentDescriptorPath) throws IOException, ClassNotFoundException {
        ClassLoader classLoader = App.class.getClassLoader();
        Enumeration<URL> resources = classLoader.getResources(componentDescriptorPath);
        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            try (InputStream is = url.openStream()) {
                _registerComponent(is);
            }
        }
    }

    @SuppressWarnings("unchecked")
    protected void _registerComponent(InputStream is) throws ClassNotFoundException {
        ClassLoader classLoader = App.class.getClassLoader();

        Element rootElement = Dom4j.readDocument(is).getRootElement();
        List<Element> components = rootElement.elements("component");
        for (Element component : components) {
            String name = trimToEmpty(component.elementText("name"));
            String componentClassName = trimToEmpty(component.elementText("class"));

            String componentLoaderClassName = trimToEmpty(component.elementText("componentLoader"));
            String tag = trimToEmpty(component.elementText("tag"));
            if (StringUtils.isEmpty(tag)) {
                tag = name;
            }

            if (StringUtils.isEmpty(name) && StringUtils.isEmpty(tag)) {
                log.warn("You have to provide name or tag for custom component");
                // skip this <component> element
                continue;
            }

            if (StringUtils.isEmpty(componentLoaderClassName) && StringUtils.isEmpty(componentClassName)) {
                log.warn("You have to provide at least <class> or <componentLoader> for custom component {} / <{}>",
                        name, tag);
                // skip this <component> element
                continue;
            }

            if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(componentClassName)) {
                Class<?> componentClass = classLoader.loadClass(componentClassName);

                if (Component.class.isAssignableFrom(componentClass)) {
                    log.trace("Register component {} class {}", name, componentClass.getCanonicalName());

                    webComponentsFactory.register(name, (Class<? extends Component>) componentClass);
                } else {
                    log.warn("Component {} is not a subclass of com.haulmont.cuba.gui.components.Component",
                            componentClassName);
                }
            }

            if (StringUtils.isNotEmpty(tag) && StringUtils.isNotEmpty(componentLoaderClassName)) {
                Class<?> componentLoaderClass = classLoader.loadClass(componentLoaderClassName);

                if (ComponentLoader.class.isAssignableFrom(componentLoaderClass)) {
                    log.trace("Register tag {} loader {}", tag, componentLoaderClass.getCanonicalName());

                    LayoutLoaderConfig.registerLoader(tag, (Class<? extends ComponentLoader>) componentLoaderClass);
                } else {
                    log.warn(
                            "Component loader {} is not a subclass of com.haulmont.cuba.gui.xml.layout.ComponentLoader",
                            componentLoaderClassName);
                }
            }
        }

        _loadWindowLoaders(rootElement);
    }

    @SuppressWarnings("unchecked")
    protected void _loadWindowLoaders(Element rootElement) {
        Class loader = loadWindowLoader(rootElement, WINDOW_LOADER_EL);
        if (loader != null) {
            LayoutLoaderConfig.registerWindowLoader(loader);
        }

        loader = loadWindowLoader(rootElement, FRAME_LOADER_EL);
        if (loader != null) {
            LayoutLoaderConfig.registerFrameLoader(loader);
        }

        loader = loadWindowLoader(rootElement, EDITOR_LOADER_EL);
        if (loader != null) {
            LayoutLoaderConfig.registerEditorLoader(loader);
        }

        loader = loadWindowLoader(rootElement, LOOKUP_LOADER_EL);
        if (loader != null) {
            LayoutLoaderConfig.registerLookupLoader(loader);
        }
    }

    protected Class loadWindowLoader(Element rootElement, String loaderElem) {
        ClassLoader classLoader = App.class.getClassLoader();

        Element elem = rootElement.element(loaderElem);
        if (elem == null) {
            return null;
        }

        String loaderClass = elem.element("class").getStringValue();
        try {
            Class clazz = classLoader.loadClass(loaderClass);

            if (loaders.get(loaderElem).isAssignableFrom(clazz)) {
                //noinspection unchecked
                return clazz;
            }

            log.warn("Class {} is not suitable as {}", loaderClass, loaderElem);
        } catch (ClassNotFoundException e) {
            log.warn("Unable to load window loader class: {}", loaderClass);
        }

        return null;
    }
}