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 292615 2005-09-30 03:40:16Z antonio $
*/
public class JXPathBindingManager extends AbstractLogEnabled implements
BindingManager, Contextualizable, Serviceable, Disposable, Initializable, Configurable,
ThreadSafe {
   
    private static final String PREFIX = "CocoonFormBinding:";
   
    private ServiceManager manager;
   
    private DatatypeManager datatypeManager;
   
    private Configuration configuration;
   
    private SimpleServiceSelector bindingBuilderSelector;
   
    private CacheManager cacheManager;
   
    private Context avalonContext;
   
    private 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.setLocalLibary(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[0]);
        }
       
        /**
         * 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.