blob: e28b3dcac213606c6237b38584ffc918ce7a280c [file] [log] [blame]
// Copyright 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.tapestry.resolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tapestry.ApplicationRuntimeException;
import org.apache.tapestry.ILocation;
import org.apache.tapestry.INamespace;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.IResourceLocation;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.spec.IComponentSpecification;
/**
* Utility class that understands the rules of component types (which
* may optionally have a library prefix) and can resolve
* the type to a {@link org.apache.tapestry.INamespace} and a
* {@link org.apache.tapestry.spec.IComponentSpecification}.
*
* <p>Like {@link org.apache.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>As declared in the application specification
* <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)
* <li>By searching the framework namespace
* </ul>
*
* The search for components in library namespaces is more abbreviated:
* <li>As declared in the library specification
* <li><i>type</i>.jwc in the same folder as the library specification
* <li>By searching the framework namespace
* </ul>
*
*
* @author Howard Lewis Ship
* @version $Id$
* @since 3.0
*
**/
public class ComponentSpecificationResolver extends AbstractSpecificationResolver
{
private static final Log LOG = LogFactory.getLog(ComponentSpecificationResolver.class);
private String _type;
public ComponentSpecificationResolver(IRequestCycle cycle)
{
super(cycle);
}
protected void reset()
{
_type = null;
super.reset();
}
/**
* 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 cycle current request cycle
* @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()
*
**/
public void resolve(
IRequestCycle cycle,
INamespace containerNamespace,
String type,
ILocation location)
{
int colonx = type.indexOf(':');
if (colonx > 0)
{
String libraryId = type.substring(0, colonx);
String simpleType = type.substring(colonx + 1);
resolve(cycle, containerNamespace, libraryId, simpleType, location);
}
else
resolve(cycle, containerNamespace, null, type, location);
}
/**
* Like {@link #resolve(org.apache.tapestry.IRequestCycle, org.apache.tapestry.INamespace, java.lang.String, org.apache.tapestry.ILocation)},
* but used when the type has already been parsed into a library id and a simple type.
*
* @param cycle current request cycle
* @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 (without a library prefix)
* @param location of reference to be resolved
* @throws ApplicationRuntimeException if the type cannot be resolved
*
**/
public void resolve(
IRequestCycle cycle,
INamespace containerNamespace,
String libraryId,
String type,
ILocation location)
{
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));
else
searchForComponent(cycle);
// If not found after search, check to see if it's in
// the framework instead.
if (getSpecification() == null)
{
throw new ApplicationRuntimeException(
Tapestry.format(
"Namespace.no-such-component-type",
type,
namespace.getNamespaceId()),
location,
null);
}
}
private void searchForComponent(IRequestCycle cycle)
{
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));
return;
}
IComponentSpecification specification =
getDelegate().findComponentSpecification(cycle, namespace, _type);
setSpecification(specification);
// 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();
IComponentSpecification specification = getSpecification();
if (LOG.isDebugEnabled())
LOG.debug(
"Installing component type "
+ _type
+ " into "
+ namespace
+ " as "
+ specification);
namespace.installComponentSpecification(_type, specification);
}
}