Package org.apache.cocoon.forms.binding

Source Code of org.apache.cocoon.forms.binding.JXPathBindingManager$Assistant

/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* 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.apache.cocoon.forms.binding;

import java.util.ArrayList;
import java.util.Stack;

import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.components.LifecycleHelper;
import org.apache.cocoon.forms.CacheManager;
import org.apache.cocoon.forms.binding.library.Library;
import org.apache.cocoon.forms.binding.library.LibraryException;
import org.apache.cocoon.forms.binding.library.LibraryManager;
import org.apache.cocoon.forms.binding.library.LibraryManagerImpl;
import org.apache.cocoon.forms.datatype.DatatypeManager;
import org.apache.cocoon.forms.util.DomHelper;
import org.apache.cocoon.forms.util.SimpleServiceSelector;
import org.apache.cocoon.util.location.LocationAttributes;
import org.apache.commons.lang.exception.NestableRuntimeException;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceResolver;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;

/**
* JXPathBindingManager provides an implementation of {@link BindingManager}by
* usage of the <a href="http://jakarta.apache.org/commons/jxpath/index.html">
* JXPath package </a>.
*
* @version $Id: JXPathBindingManager.java 372625 2006-01-26 21:57:02Z mpfingsthorn $
*/
public class JXPathBindingManager extends AbstractLogEnabled implements
BindingManager, Contextualizable, Serviceable, Disposable, Initializable, Configurable,
ThreadSafe {

    private static final String PREFIX = "CocoonFormBinding:";

    protected ServiceManager manager;

    protected DatatypeManager datatypeManager;

    private Configuration configuration;

    protected SimpleServiceSelector bindingBuilderSelector;

    private CacheManager cacheManager;

    private Context avalonContext;

    protected LibraryManagerImpl libraryManager;

    public void contextualize(Context context) throws ContextException {
        this.avalonContext = context;
    }

    public void service(ServiceManager manager) throws ServiceException {
        this.manager = manager;
        this.datatypeManager = (DatatypeManager) manager.lookup(DatatypeManager.ROLE);
        this.cacheManager = (CacheManager) manager.lookup(CacheManager.ROLE);
    }

    public void configure(Configuration configuration)
    throws ConfigurationException {
        this.configuration = configuration;
    }

    public void initialize() throws Exception {
        bindingBuilderSelector = new SimpleServiceSelector("binding",
                JXPathBindingBuilderBase.class);
        LifecycleHelper.setupComponent(bindingBuilderSelector,
                getLogger(),
                this.avalonContext,
                this.manager,
                configuration.getChild("bindings"));

        libraryManager = new LibraryManagerImpl();
        libraryManager.setBindingManager(this);
        LifecycleHelper.setupComponent(libraryManager,
                getLogger(),
                this.avalonContext,
                this.manager,
                configuration.getChild("library"));
    }

    public Binding createBinding(Source source) throws BindingException {
        Binding binding = (Binding) this.cacheManager.get(source, PREFIX);

        if (binding != null && !binding.isValid())
            binding = null; //invalidate

        if (binding == null) {
            try {
                InputSource is = new InputSource(source.getInputStream());
                is.setSystemId(source.getURI());

                Document doc = DomHelper.parse(is, this.manager);
                Element rootElm = doc.getDocumentElement();
                if (BindingManager.NAMESPACE.equals(rootElm.getNamespaceURI())) {
                    binding = getBuilderAssistant()
                    .getBindingForConfigurationElement(rootElm);
                    ((JXPathBindingBase) binding).enableLogging(getLogger());
                    if (getLogger().isDebugEnabled()) {
                        getLogger().debug("Creation of new binding finished. " + binding);
                    }
                } else {
                    if (getLogger().isDebugEnabled()) {
                        getLogger().debug("Root Element of said binding file is in wrong namespace.");
                    }
                }

                this.cacheManager.set(binding, source, PREFIX);
            } catch (BindingException e) {
                throw e;
            } catch (Exception e) {
                throw new BindingException("Error creating binding from " +
                        source.getURI(), e);
            }
        }
        return binding;
    }

    public Binding createBinding(String bindingURI) throws BindingException {
        SourceResolver sourceResolver = null;
        Source source = null;

        try {
            try {
                sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
                source = sourceResolver.resolveURI(bindingURI);
            } catch (Exception e) {
                throw new BindingException("Error resolving binding source: " +
                        bindingURI);
            }
            return createBinding(source);
        } finally {
            if (source != null) {
                sourceResolver.release(source);
            }
            if (sourceResolver != null) {
                manager.release(sourceResolver);
            }
        }
    }

    public Assistant getBuilderAssistant() {
        return new Assistant();
    }

    public void dispose() {
        if (this.bindingBuilderSelector != null) {
            this.bindingBuilderSelector.dispose();
            this.bindingBuilderSelector = null;
        }
        this.manager.release(this.datatypeManager);
        this.datatypeManager = null;
        this.manager.release(this.cacheManager);
        this.cacheManager = null;
        this.manager = null;
    }

    /**
     * Assistant Inner class discloses enough features to the created
     * childBindings to recursively
     *
     * This patterns was chosen to prevent Inversion Of Control between this
     * factory and its builder classes (that could be provided by third
     * parties.)
     */
    /*
     * NOTE: To get access to the logger in this inner class you must not call
     * getLogger() as with JDK 1.3 this gives a NoSuchMethod error. You need to
     * implement an explicit access method for the logger in the outer class.
     */
    public class Assistant {

        private BindingBuilderContext context = new BindingBuilderContext();
        private Stack contextStack = new Stack();
       
        private JXPathBindingBuilderBase getBindingBuilder(String bindingType)
        throws BindingException {
            try {
                return (JXPathBindingBuilderBase) bindingBuilderSelector
                .select(bindingType);
            } catch (ServiceException e) {
                throw new BindingException(
                        "Cannot handle binding element with " + "name \""
                        + bindingType + "\".", e);
            }
        }

        /**
         * Creates a {@link Binding} following the specification in the
         * provided config element.
         */
        public JXPathBindingBase getBindingForConfigurationElement(
                Element configElm) throws BindingException {
            String bindingType = configElm.getLocalName();
            JXPathBindingBuilderBase bindingBuilder = getBindingBuilder(bindingType);

            boolean flag = false;
            if (context.getLocalLibrary() == null) {
                Library lib = new Library(libraryManager);
                context.setLocalLibrary(lib);
                lib.setAssistant(getBuilderAssistant());
                lib.setSourceURI(LocationAttributes.getURI(configElm));
                flag = true;
            }

            if (context.getLocalLibrary() != null && configElm.hasAttribute("extends")) {
                try {
                    context.setSuperBinding(context.getLocalLibrary().getBinding(configElm.getAttribute("extends")));

                } catch(LibraryException e) {
                    // throw new RuntimeException("Error extending binding! (at "+DomHelper.getLocation(configElm)+")", e);
                    throw new NestableRuntimeException("Error extending binding! (at " + DomHelper.getLocation(configElm) + ")", e);
                }
            } else {
                context.setSuperBinding(null);
            }

            JXPathBindingBase childBinding = bindingBuilder.buildBinding(configElm, this);

            if (flag && childBinding != null) {
                childBinding.setEnclosingLibrary(context.getLocalLibrary());
            }

            // this might get called unnecessarily, but solves issues with the libraries
            if (childBinding != null) {
                childBinding.enableLogging(getLogger());
            }
            return childBinding;
        }

        private JXPathBindingBase[] mergeBindings(JXPathBindingBase[] existing, JXPathBindingBase[] extra) {

            if (existing == null || existing.length == 0) {
                return extra;
            }
            if (extra == null || extra.length == 0) {
                return existing;
            }
            // have to do it the stupid painter way..
            ArrayList list = new ArrayList(existing.length);
            for (int i = 0; i < existing.length; i++) {
                list.add(existing[i]);
            }
            for (int i = 0; i < extra.length; i++) {
                if (extra[i].getId() == null) {
                    list.add(extra[i]);
                } else {
                    // try to replace existing one
                    boolean match = false;
                    for(int j=0; j<list.size(); j++) {
                        if(extra[i].getId().equals(((JXPathBindingBase)list.get(j)).getId())) {
                            list.set(j,extra[i]);
                            match = true;
                            break; // stop searching
                        }
                    }
                    // if no match, just add
                    if (!match) {
                        list.add(extra[i]);
                    }
                }
            } 
            return (JXPathBindingBase[])list.toArray(new JXPathBindingBase[list.size()]);
        }

        /**
         * proxy for compatibility
         *
         */
        public JXPathBindingBase[] makeChildBindings(Element parentElement) throws BindingException {
            return makeChildBindings(parentElement,new JXPathBindingBase[0]);
        }

        /**
         * Makes an array of childBindings for the child-elements of the
         * provided configuration element.
         */
        public JXPathBindingBase[] makeChildBindings(Element parentElement, JXPathBindingBase[] existingBindings)
        throws BindingException {
            if (existingBindings == null)
                existingBindings = new JXPathBindingBase[0];

            if (parentElement != null) {
                Element[] childElements = DomHelper.getChildElements(
                        parentElement, BindingManager.NAMESPACE);
                if (childElements.length > 0) {
                    JXPathBindingBase[] childBindings = new JXPathBindingBase[childElements.length];
                    for (int i = 0; i < childElements.length; i++) {

                        pushContext();
                        context.setSuperBinding(null);

                        String id = DomHelper.getAttribute(childElements[i], "id", null);
                        String path = DomHelper.getAttribute(childElements[i], "path", null);
                        if(context.getLocalLibrary()!=null && childElements[i].getAttribute("extends")!=null) {
                            try {
                                context.setSuperBinding(context.getLocalLibrary().getBinding(childElements[i].getAttribute("extends")));

                                if(context.getSuperBinding() == null) // not found in library
                                    context.setSuperBinding(getBindingByIdOrPath(id,path,existingBindings));

                            } catch(LibraryException e) {
                                throw new BindingException("Error extending binding! (at "+DomHelper.getLocation(childElements[i])+")",e);
                            }
                        }
                        childBindings[i] = getBindingForConfigurationElement(childElements[i]);
                        popContext();
                    }
                    return mergeBindings(existingBindings,childBindings);
                }
            }
            return existingBindings;
        }

        private JXPathBindingBase getBindingByIdOrPath(String id, String path, JXPathBindingBase[] bindings) {
            String name = id;
            if (name == null) {
                name = "Context:"+path;
            }
            for (int i = 0; i < bindings.length; i++) {
                if (name.equals(bindings[i].getId())) {
                    return bindings[i];
                }
            }
            return null;
        }

        public DatatypeManager getDatatypeManager() {
            return datatypeManager;
        }

        public ServiceManager getServiceManager() {
            return manager;
        }

        public LibraryManager getLibraryManager() {
            return libraryManager;
        }

        public BindingBuilderContext getContext() {
            return this.context;
        }
        private void pushContext() {
            BindingBuilderContext c = new BindingBuilderContext(context);
            contextStack.push(context);
            context = c;
        }

        private void popContext() {
            if(!contextStack.empty()) {
                context = (BindingBuilderContext)contextStack.pop();
            } else {
                context = new BindingBuilderContext();
            }
        }
    }
}
TOP

Related Classes of org.apache.cocoon.forms.binding.JXPathBindingManager$Assistant

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.