CVS: Tapestry/framework/src/net/sf/tapestry/resolver AbstractSpecificationResolver.java,NONE,1.1.2.1 PageSpecificationResolver.java,NONE,1.1.2.1 ComponentSpecificationResolver.java,NONE,1.1.2.1

Howard Lewis Ship <[email protected]>
Newsgroups gmane.comp.java.tapestry.cvs
Message-ID <[email protected]>
Update of /cvsroot/tapestry/Tapestry/framework/src/net/sf/tapestry/resolver
In directory sc8-pr-cvs1:/tmp/cvs-serv23659/framework/src/net/sf/tapestry/resolver

Added Files:
      Tag: hship-2-3
	AbstractSpecificationResolver.java 
	PageSpecificationResolver.java 
	ComponentSpecificationResolver.java 
Log Message:
Allow searches for component specifications.
Allow application specification to be in WEB-INF instead of on classpath.
Allow application to run without an application specification.

--- NEW FILE: AbstractSpecificationResolver.java ---
package net.sf.tapestry.resolver;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.tapestry.IEngine;
import net.sf.tapestry.INamespace;
import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.IResourceLocation;
import net.sf.tapestry.ISpecificationSource;
import net.sf.tapestry.Tapestry;
import net.sf.tapestry.spec.ComponentSpecification;

/**
 *  Base class for resolving a {@link net.sf.tapestry.spec.ComponentSpecification}
 *  for a particular page or component, within a specified 
 *  {@link net.sf.tapestry.INamespace}.  In some cases, a search is necessary.
 *
 *  @author Howard Lewis Ship
 *  @version $Id: AbstractSpecificationResolver.java,v 1.1.2.1 2002/12/15 16:26:12 hship Exp $
 *  @since 2.4
 *
 **/

public class AbstractSpecificationResolver
{
    private static final Log LOG = LogFactory.getLog(AbstractSpecificationResolver.class);

    private ISpecificationSource _specificationSource;

    private INamespace _namespace;

    private ComponentSpecification _specification;

    private IResourceLocation _applicationRootLocation;

    private IResourceLocation _webInfLocation;

    private IResourceLocation _webInfAppLocation;

    public AbstractSpecificationResolver(IRequestCycle cycle)
    {
        IEngine engine = cycle.getEngine();

        _specificationSource = engine.getSpecificationSource();

        _applicationRootLocation = Tapestry.getApplicationRootLocation(cycle);

        String servletName = cycle.getRequestContext().getServlet().getServletConfig().getServletName();

        _webInfLocation = _applicationRootLocation.getRelativeLocation("/WEB-INF/");

        _webInfAppLocation = _webInfLocation.getRelativeLocation(servletName + "/");
    }

    /**
     *  Returns the location of the servlet, within the
     *  servlet context.
     * 
     **/

    protected IResourceLocation getApplicationRootLocation()
    {
        return _applicationRootLocation;
    }

    /**
     *  Invoked in subclasses to identify the resolved namespace.
     * 
     **/

    protected void setNamespace(INamespace namespace)
    {
        _namespace = namespace;
    }

    /**
     *  Returns the resolve namespace.
     * 
     **/

    public INamespace getNamespace()
    {
        return _namespace;
    }

    /**
     *  Returns the specification source for the running application.
     * 
     **/

    protected ISpecificationSource getSpecificationSource()
    {
        return _specificationSource;
    }

    /**
     *  Returns the location of /WEB-INF/, in the servlet context.
     * 
     **/

    protected IResourceLocation getWebInfLocation()
    {
        return _webInfLocation;
    }

    /**
     *  Returns the location of the application-specific subdirectory, under
     *  /WEB-INF/, in the servlet context.
     * 
     **/

    protected IResourceLocation getWebInfAppLocation()
    {
        return _webInfAppLocation;
    }

    /**
     *  Returns the resolved specification.
     * 
     **/

    public ComponentSpecification getSpecification()
    {
        return _specification;
    }

    /**
     *  Invoked in subclass to set the final specification the initial
     *  inputs are resolved to.
     * 
     **/

    protected void setSpecification(ComponentSpecification specification)
    {
        _specification = specification;
    }


    /**
     *  Clears the namespace, specification and simpleName properties.
     * 
     **/

    protected void reset()
    {
        _namespace = null;
        _specification = null;
    }

}

--- NEW FILE: PageSpecificationResolver.java ---
package net.sf.tapestry.resolver;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.tapestry.ApplicationRuntimeException;
import net.sf.tapestry.INamespace;
import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.IResourceLocation;
import net.sf.tapestry.Tapestry;
import net.sf.tapestry.html.BasePage;
import net.sf.tapestry.spec.ComponentSpecification;

/**
 *  Performs the tricky work of resolving a page name to a page specification.
 *  The search for pages in the application namespace is the most complicated,
 *  since Tapestry searches for pages that aren't explicitly defined in the
 *  application specification.  The search, based on the <i>simple-name</i>
 *  of the page, goes as follows:
 * 
 *  <ul>
 *  <li><i>simple-name</i>.page in the same folder as the application specification
 *  <li><i>simple-name</i> page in the WEB-INF/<i>servlet-name</i> directory of the context root
 *  <li><i>simple-name</i>.page in WEB-INF
 *  <li><i>simple-name</i>.page in the application root (within the context root)
 *  <li><i>simple-name</i>.html as a template in the application root, 
 *      for which an implicit specification is generated
 *  </ul>
 * 
 *  <p>If none of these work out, then the page is searched for in the framework namespace.
 *  This is used to find default implementations of pages such as Exception and StaleLink.
 *
 *  @see net.sf.tapestry.IPageSource
 *  @author Howard Lewis Ship
 *  @version $Id: PageSpecificationResolver.java,v 1.1.2.1 2002/12/15 16:26:12 hship Exp $
 *  @since 2.4
 *
 **/

public class PageSpecificationResolver extends AbstractSpecificationResolver
{
    private static final Log LOG = LogFactory.getLog(PageSpecificationResolver.class);

    private String _simpleName;

    public PageSpecificationResolver(IRequestCycle cycle)
    {
        super(cycle);
    }

    /**
     *  Resolve the name (which may have a library id prefix) to a namespace
     *  (see {@link #getNamespace()}) and a specification (see {@link #getSpecification()}).
     * 
     *  @throws ApplicationRuntimeException if the name cannot be resolved
     * 
     **/

    public void resolve(String prefixedName)
    {
        reset();

        INamespace namespace = null;

        int colonx = prefixedName.indexOf(':');

        if (colonx > 0)
        {
            _simpleName = prefixedName.substring(colonx + 1);
            String namespaceId = prefixedName.substring(0, colonx);

            if (namespaceId.equals(INamespace.FRAMEWORK_NAMESPACE))
                namespace = getSpecificationSource().getFrameworkNamespace();
            else
                namespace = getSpecificationSource().getApplicationNamespace().getChildNamespace(namespaceId);
        }
        else
        {
            _simpleName = prefixedName;

            namespace = getSpecificationSource().getApplicationNamespace();
        }

        setNamespace(namespace);

        if (namespace.containsPage(_simpleName))
        {
            setSpecification(namespace.getPageSpecification(_simpleName));
            return;
        }

        // Not defined in the specification, so it's time to hunt it down.

        searchForPage();

        if (getSpecification() == null)
            throw new ApplicationRuntimeException(
                Tapestry.getString("Namespace.no-such-page", _simpleName, namespace.getNamespaceId()));

    }

    private void searchForPage()
    {
        INamespace namespace = getNamespace();

        if (LOG.isDebugEnabled())
            LOG.debug("Resolving unknown page '" + _simpleName + "' in " + namespace);

        String expectedName = _simpleName + ".page";

        IResourceLocation namespaceLocation = namespace.getSpecificationLocation();

        // See if there's a specification file in the same folder
        // as the library or application specification that's
        // supposed to contain the page.

        if (found(namespaceLocation.getRelativeLocation(expectedName)))
            return;

        // If not for the (unnamed) application specification, then return ... which will
        // cause an exception.

        if (!namespace.isApplicationNamespace())
            return;

        // The application namespace gets some extra searching.

        if (found(getWebInfAppLocation().getRelativeLocation(expectedName)))
            return;

        if (found(getWebInfLocation().getRelativeLocation(expectedName)))
            return;

        if (found(getApplicationRootLocation().getRelativeLocation(expectedName)))
            return;

        // The wierd one ... where we see if there's an HTML file in the application root location.

        String templateName = _simpleName + ".html";

        IResourceLocation templateLocation = getApplicationRootLocation().getRelativeLocation(templateName);

        if (templateLocation.getResourceURL() != null)
        {
            setupImplicitPage(templateLocation);
            return;
        }

        // Not found in application namespace, so maybe its a framework page.

        INamespace framework = getSpecificationSource().getFrameworkNamespace();

        if (framework.containsPage(_simpleName))
        {
            if (LOG.isDebugEnabled())
                LOG.debug("Found " + _simpleName + " in framework namespace.");

            setNamespace(framework);

            // Note:  This implies that normal lookup rules don't work
            // for the framework!  Framework pages must be
            // defined in the framework library specification.

            setSpecification(framework.getPageSpecification(_simpleName));
        }

    }

    private void setupImplicitPage(IResourceLocation location)
    {
        if (LOG.isDebugEnabled())
            LOG.debug("Found HTML template at " + location);

        ComponentSpecification specification = new ComponentSpecification();
        specification.setComponentClassName(BasePage.class.getName());
        specification.setPageSpecification(true);
        specification.setSpecificationLocation(location);

        setSpecification(specification);

        install();
    }

    private boolean found(IResourceLocation location)
    {
        if (LOG.isDebugEnabled())
            LOG.debug("Checking: " + location);

        if (location.getResourceURL() == null)
            return false;

        setSpecification(getSpecificationSource().getPageSpecification(location));

        install();

        return true;
    }

    private void install()
    {
        INamespace namespace = getNamespace();
        ComponentSpecification specification = getSpecification();

        if (LOG.isDebugEnabled())
            LOG.debug("Installing page " + _simpleName + " into " + namespace + " as " + specification);

        namespace.installPageSpecification(_simpleName, specification);
    }

}

--- NEW FILE: ComponentSpecificationResolver.java ---
package net.sf.tapestry.resolver;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.tapestry.ApplicationRuntimeException;
import net.sf.tapestry.INamespace;
import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.IResourceLocation;
import net.sf.tapestry.PageLoaderException;
import net.sf.tapestry.Tapestry;
import net.sf.tapestry.spec.ComponentSpecification;

/**
 *  Utility class that understands the rules of component types (which
 *  may optionally have a library prefix) and can resolve 
 *  the type to a {@link net.sf.tapestry.INamespace} and a 
 *  {@link net.sf.tapestry.spec.ComponentSpecification}.
 * 
 *  <p>Like {@link net.sf.tapestry.resolver.PageSpecificationResolver},
 *  if the component is not defined explicitly in the namespace, a search
 *  may occur:
 * 
 *  Performs the tricky work of resolving a page name to a page specification.
 *  The search for pages in the application namespace is the most complicated,
 *  since Tapestry searches for pages that aren't explicitly defined in the
 *  application specification.  The search, based on the <i>simple-name</i>
 *  of the page, goes as follows:
 * 
 *  <ul>
 *  <li><i>type</i>.jwc in the same folder as the application specification
 *  <li><i>type</i> jwc in the WEB-INF/<i>servlet-name</i> directory of the context root
 *  <li><i>type</i>.jwc in WEB-INF
 *  <li><i>type</i>.jwc in the application root (within the context root)
  *  </ul> 
 * 
 *  @author Howard Lewis Ship
 *  @version $Id: ComponentSpecificationResolver.java,v 1.1.2.1 2002/12/15 16:26:13 hship Exp $
 *  @since 2.4
 *
 **/

public class ComponentSpecificationResolver extends AbstractSpecificationResolver
{
    private static final Log LOG = LogFactory.getLog(ComponentSpecificationResolver.class);

    private String _type;

    public ComponentSpecificationResolver(IRequestCycle cycle)
    {
        super(cycle);
    }

    /**
     *  Passed the namespace of a container (to resolve the type in)
     *  and the type to resolve, performs the processing.  A "bare type"
     *  (without a library prefix) may be in the containerNamespace,
     *  or the framework namespace
     *  (a search occurs in that order).
     * 
     *  @param containerNamespace namespace that may contain
     *  a library referenced in the type
     *  @param type the component specification
     *  to  find, either a simple name, or prefixed with a library id
     *  (defined for the container namespace)
     * 
     *  @see #getNamespace()
     *  @see #getSpecification()
     *  @throws PageLoaderException if the type cannot be resolved
     * 
     **/

    public void resolve(INamespace containerNamespace, String type) throws PageLoaderException
    {
        int colonx = type.indexOf(':');

        if (colonx > 0)
        {
            String libraryId = type.substring(0, colonx);
            String simpleType = type.substring(colonx + 1);

            resolve(containerNamespace, libraryId, simpleType);
        }
        else
            resolve(containerNamespace, null, type);
    }

    /**
     *  Like {@link #resolve(INamespace, String)}, but used when the type has already
     *  been parsed into a library id and a simple type.
     * 
     *  @param containerNamespace namespace that may contain
     *  a library referenced in the type
     *  @param libraryId the library id within the container namespace, or null
     *  @param type the component specification
     *  to  find as a simple name
     *  @throws ApplicationRuntimeException if the type cannot be resolved
     * 
     **/

    public void resolve(INamespace containerNamespace, String libraryId, String type)
    {
        reset();
        _type = type;

        INamespace namespace = null;

        if (libraryId != null)
            namespace = containerNamespace.getChildNamespace(libraryId);
        else
            namespace = containerNamespace;

        setNamespace(namespace);

        if (namespace.containsComponentType(type))
        {
            setSpecification(namespace.getComponentSpecification(type));
            return;
        }

        searchForComponent();

        // If not found after search, check to see if it's in
        // the framework instead.

        if (getSpecification() == null)
        {

            throw new ApplicationRuntimeException(
                Tapestry.getString("Namespace.no-such-component-type", type, namespace.getNamespaceId()));

        }
    }

    private void searchForComponent()
    {
        INamespace namespace = getNamespace();

        if (LOG.isDebugEnabled())
            LOG.debug("Resolving unknown component '" + _type + "' in " + namespace);

        String expectedName = _type + ".jwc";
        IResourceLocation namespaceLocation = namespace.getSpecificationLocation();

        // Look for appropriate file in same folder as the library (or application)
        // specificaiton.

        if (found(namespaceLocation.getRelativeLocation(expectedName)))
            return;

        if (namespace.isApplicationNamespace())
        {

            // The application namespace gets some extra searching.

            if (found(getWebInfAppLocation().getRelativeLocation(expectedName)))
                return;

            if (found(getWebInfLocation().getRelativeLocation(expectedName)))
                return;

            if (found(getApplicationRootLocation().getRelativeLocation(expectedName)))
                return;
        }

        // Not in the library or app spec; does it match a component
        // provided by the Framework?

        INamespace framework = getSpecificationSource().getFrameworkNamespace();

        if (framework.containsComponentType(_type))
            setSpecification(framework.getComponentSpecification(_type));

        // If not found by here, an exception will be thrown.

    }

    private boolean found(IResourceLocation location)
    {
        if (LOG.isDebugEnabled())
            LOG.debug("Checking: " + location);

        if (location.getResourceURL() == null)
            return false;

        setSpecification(getSpecificationSource().getComponentSpecification(location));

        install();

        return true;
    }

    private void install()
    {
        INamespace namespace = getNamespace();
        ComponentSpecification specification = getSpecification();

        if (LOG.isDebugEnabled())
            LOG.debug("Installing component type " + _type + " into " + namespace + " as " + specification);

        namespace.installComponentSpecification(_type, specification);
    }
}



-------------------------------------------------------
This sf.net email is sponsored by:
With Great Power, Comes Great Responsibility 
Learn to use your power at OSDN's High Performance Computing Channel
http://hpc.devchannel.org/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.