001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.markup.resolver;
018:
019: import java.util.HashMap;
020: import java.util.HashSet;
021: import java.util.Map;
022: import java.util.Set;
023:
024: import org.apache.wicket.Component;
025: import org.apache.wicket.MarkupContainer;
026: import org.apache.wicket.Page;
027: import org.apache.wicket.PageParameters;
028: import org.apache.wicket.ResourceReference;
029: import org.apache.wicket.application.IClassResolver;
030: import org.apache.wicket.markup.ComponentTag;
031: import org.apache.wicket.markup.MarkupStream;
032: import org.apache.wicket.markup.html.PackageResource;
033: import org.apache.wicket.markup.html.WebMarkupContainer;
034: import org.apache.wicket.markup.html.link.BookmarkablePageLink;
035: import org.apache.wicket.markup.html.link.ExternalLink;
036: import org.apache.wicket.markup.parser.filter.WicketLinkTagHandler;
037: import org.apache.wicket.protocol.http.RequestUtils;
038: import org.apache.wicket.util.lang.Packages;
039: import org.apache.wicket.util.string.Strings;
040: import org.slf4j.Logger;
041: import org.slf4j.LoggerFactory;
042:
043: /**
044: * The AutoLinkResolver is responsible to handle automatic link resolution. Tags
045: * are marked "autolink" by the MarkupParser for all tags with href attribute,
046: * such as anchor and link tags with no explicit wicket id. E.g. <a
047: * href="Home.html">
048: * <p>
049: * If href points to a *.html file, a BookmarkablePageLink will automatically be
050: * created, except for absolut paths, where an ExternalLink is created.
051: * <p>
052: * If href points to a *.html file, it resolves the given URL by searching for a
053: * page class, either relative or absolute, specified by the href attribute of
054: * the tag. If relative the href URL must be relative to the package containing
055: * the associated page. An exception is thrown if no Page class was found.
056: * <p>
057: * If href is no *.html file a static reference to the resource is created.
058: *
059: * @see org.apache.wicket.markup.parser.filter.WicketLinkTagHandler
060: *
061: * @author Juergen Donnerstag
062: * @author Eelco Hillenius
063: */
064: public final class AutoLinkResolver implements IComponentResolver {
065: /**
066: * Abstract implementation that has a helper method for creating a resource
067: * reference.
068: */
069: public static abstract class AbstractAutolinkResolverDelegate
070: implements IAutolinkResolverDelegate {
071: /**
072: * Creates a new auto component that references a package resource.
073: *
074: * @param container
075: * the parent container
076: * @param autoId
077: * the automatically generated id for the auto component
078: * @param pathInfo
079: * the path info object that contains information about the
080: * link reference
081: * @param attribute
082: * the attribute to replace the value of
083: * @return a new auto component or null if the path was absolute
084: */
085: protected final Component newPackageResourceReferenceAutoComponent(
086: final MarkupContainer container, final String autoId,
087: final PathInfo pathInfo, final String attribute) {
088: if (!pathInfo.absolute) {
089: // Href is relative. Create a resource reference pointing at
090: // this file
091:
092: // <wicket:head> components are handled differently. We can
093: // not use the container, because it is the container the
094: // header has been added to (e.g. the Page). What we need
095: // however, is the component (e.g. a Panel) which
096: // contributed it.
097: Class clazz = container.getMarkupStream()
098: .getContainerClass();
099:
100: // However if the markup stream is a merged markup stream
101: // (inheritance),
102: // than we need the class of the markup file which contained the
103: // tag.
104: if (container.getMarkupStream().getTag()
105: .getMarkupClass() != null) {
106: clazz = container.getMarkupStream().getTag()
107: .getMarkupClass();
108: }
109:
110: // Create the component implementing the link
111: ResourceReferenceAutolink autoLink = new ResourceReferenceAutolink(
112: autoId, clazz, pathInfo.reference, attribute);
113: if (autoLink.resourceReference != null) {
114: // if the resource reference is null, it means that it the
115: // reference was not found as a package resource
116: return autoLink;
117: }
118: }
119: // else we can't have absolute resource references, at least not at
120: // this time
121:
122: // fall back on default processing
123: return null;
124: }
125: }
126:
127: /**
128: * Autolink components delegate component resolution to their parent
129: * components. Reason: autolink tags don't have wicket:id and users wouldn't
130: * know where to add the component to.
131: *
132: * @author Juergen Donnerstag
133: */
134: public final static class AutolinkBookmarkablePageLink extends
135: BookmarkablePageLink {
136: private static final long serialVersionUID = 1L;
137:
138: private final String anchor;
139:
140: /**
141: * When using <wicket:link> to let Wicket lookup for pages and create
142: * the related links, it's not possible to change the "setAutoEnable"
143: * property, which defaults to true. This affects the prototype because,
144: * sometimes designers _want_ links to be enabled.
145: */
146: public static boolean autoEnable = true;
147:
148: /**
149: * Construct
150: *
151: * @see BookmarkablePageLink#BookmarkablePageLink(String, Class,
152: * PageParameters)
153: *
154: * @param id
155: * @param pageClass
156: * @param parameters
157: * @param anchor
158: */
159: public AutolinkBookmarkablePageLink(final String id,
160: final Class pageClass, final PageParameters parameters,
161: final String anchor) {
162: super (id, pageClass, parameters);
163: this .anchor = anchor;
164: setAutoEnable(autoEnable);
165: }
166:
167: /**
168: * @see org.apache.wicket.MarkupContainer#isTransparentResolver()
169: */
170: public boolean isTransparentResolver() {
171: return true;
172: }
173:
174: /**
175: *
176: * @see org.apache.wicket.markup.html.link.BookmarkablePageLink#getURL()
177: */
178: protected CharSequence getURL() {
179: CharSequence url = super .getURL();
180: if (anchor != null) {
181: url = url + anchor;
182: }
183:
184: return url;
185: }
186: }
187:
188: /**
189: * Interface to delegate the actual resolving of auto components to.
190: */
191: public static interface IAutolinkResolverDelegate {
192: /**
193: * Returns a new auto component based on the pathInfo object. The auto
194: * component must have the autoId assigned as it's id. Should return
195: * null in case the component could not be created as expected and the
196: * default resolving should take place.
197: *
198: * @param container
199: * the parent container
200: * @param autoId
201: * the automatically generated id for the auto component
202: * @param pathInfo
203: * the path info object that contains information about the
204: * link reference
205: * @return a new auto component or null in case this method couldn't
206: * resolve to a proper auto component
207: */
208: Component newAutoComponent(final MarkupContainer container,
209: final String autoId, final PathInfo pathInfo);
210: }
211:
212: /**
213: * Encapsulates different aspects of a path. For instance, the path
214: * <code>org.apache.wicket.markup.html.tree.Tree/tree.css</code> has
215: * extension <code>css</code>, is relative (absolute == true) and has no
216: * page parameters.
217: */
218: public static final class PathInfo {
219: /** whether the reference is absolute. */
220: private final boolean absolute;
221:
222: /** An optional anchor like #top */
223: private final String anchor;
224:
225: /** The extension if any. */
226: private final String extension;
227:
228: /** The optional page parameters. */
229: private final PageParameters pageParameters;
230:
231: /** The path exluding any parameters. */
232: private final String path;
233:
234: /** The original reference (e.g the full value of a href attribute). */
235: private final String reference;
236:
237: /**
238: * Construct.
239: *
240: * @param reference
241: * the original reference (e.g the full value of a href
242: * attribute)
243: */
244: public PathInfo(final String reference) {
245: this .reference = reference;
246: // If href contains URL query parameters ..
247: String infoPath;
248: // get the query string
249: int queryStringPos = reference.indexOf("?");
250: if (queryStringPos != -1) {
251: final String queryString = reference
252: .substring(queryStringPos + 1);
253: pageParameters = new PageParameters();
254: RequestUtils.decodeParameters(queryString,
255: pageParameters);
256: infoPath = reference.substring(0, queryStringPos);
257: } else {
258: pageParameters = null;
259: infoPath = reference;
260: }
261:
262: absolute = (infoPath.startsWith("/") || infoPath
263: .startsWith("\\"));
264:
265: // remove file extension, but remember it
266: String extension = null;
267: int pos = infoPath.lastIndexOf(".");
268: if (pos != -1) {
269: extension = infoPath.substring(pos + 1);
270: infoPath = infoPath.substring(0, pos);
271: }
272:
273: String anchor = null;
274: if (extension != null) {
275: pos = extension.indexOf('#');
276: if (pos != -1) {
277: anchor = extension.substring(pos);
278: extension = extension.substring(0, pos);
279: }
280: }
281:
282: path = infoPath;
283: this .extension = extension;
284: this .anchor = anchor;
285: }
286:
287: /**
288: * Gets the anchor (e.g. #top)
289: *
290: * @return anchor
291: */
292: public final String getAnchor() {
293: return anchor;
294: }
295:
296: /**
297: * Gets extension.
298: *
299: * @return extension
300: */
301: public final String getExtension() {
302: return extension;
303: }
304:
305: /**
306: * Gets pageParameters.
307: *
308: * @return pageParameters
309: */
310: public final PageParameters getPageParameters() {
311: return pageParameters;
312: }
313:
314: /**
315: * Gets path.
316: *
317: * @return path
318: */
319: public final String getPath() {
320: return path;
321: }
322:
323: /**
324: * Gets reference.
325: *
326: * @return reference
327: */
328: public final String getReference() {
329: return reference;
330: }
331:
332: /**
333: * Gets absolute.
334: *
335: * @return absolute
336: */
337: public final boolean isAbsolute() {
338: return absolute;
339: }
340: }
341:
342: /**
343: * Resolves to anchor/ link components.
344: */
345: private static final class AnchorResolverDelegate extends
346: AbstractAutolinkResolverDelegate {
347: /** the attribute to fetch. */
348: private static final String attribute = "href";
349:
350: /**
351: * Set of supported extensions for creating bookmarkable page links.
352: * Anything that is not in this list will be handled as a resource
353: * reference.
354: */
355: private final Set supportedPageExtensions = new HashSet(4);
356:
357: /**
358: * Construct.
359: */
360: public AnchorResolverDelegate() {
361: // Initialize supported list of file name extension which'll create
362: // bookmarkable pages
363: supportedPageExtensions.add("html");
364: supportedPageExtensions.add("xml");
365: supportedPageExtensions.add("wml");
366: supportedPageExtensions.add("svg");
367: }
368:
369: /**
370: * @see org.apache.wicket.markup.resolver.AutoLinkResolver.IAutolinkResolverDelegate#newAutoComponent(org.apache.wicket.MarkupContainer,
371: * java.lang.String,
372: * org.apache.wicket.markup.resolver.AutoLinkResolver.PathInfo)
373: */
374: public Component newAutoComponent(
375: final MarkupContainer container, final String autoId,
376: PathInfo pathInfo) {
377: if ((pathInfo.extension != null)
378: && supportedPageExtensions
379: .contains(pathInfo.extension)) {
380: // Obviously a href like href="myPkg.MyLabel.html" will do as
381: // well. Wicket will not throw an exception. It accepts it.
382: String infoPath = Strings.replaceAll(pathInfo.path,
383: "/", ".").toString();
384:
385: Page page = container.getPage();
386: final IClassResolver defaultClassResolver = page
387: .getApplication().getApplicationSettings()
388: .getClassResolver();
389:
390: String className;
391: if (!infoPath.startsWith(".")) {
392: // Href is relative. Resolve the url given relative to the
393: // current page
394: className = Packages.extractPackageName(page
395: .getClass())
396: + "." + infoPath;
397: } else {
398: // Href is absolute. If class with the same absolute path
399: // exists, use it. Else don't change the href.
400: className = infoPath.substring(1);
401: }
402:
403: try {
404: final Class clazz = defaultClassResolver
405: .resolveClass(className);
406: return new AutolinkBookmarkablePageLink(autoId,
407: clazz, pathInfo.pageParameters,
408: pathInfo.anchor);
409: } catch (ClassNotFoundException ex) {
410: log.warn("Did not find corresponding java class: "
411: + className);
412: // fall through
413: }
414:
415: // Make sure base markup pages (inheritance) are handled correct
416: MarkupContainer parentWithContainer = container;
417: if (container.getParent() != null) {
418: parentWithContainer = container
419: .findParentWithAssociatedMarkup();
420: }
421: if ((parentWithContainer instanceof Page)
422: && !infoPath.startsWith(".")
423: && page.getMarkupStream().isMergedMarkup()) {
424: Class clazz = container.getMarkupStream().getTag()
425: .getMarkupClass();
426: if (clazz != null) {
427: // Href is relative. Resolve the url given relative to
428: // the current page
429: className = Packages.extractPackageName(clazz)
430: + "." + infoPath;
431:
432: try {
433: clazz = defaultClassResolver
434: .resolveClass(className);
435: return new AutolinkBookmarkablePageLink(
436: autoId, clazz, pathInfo
437: .getPageParameters(),
438: pathInfo.anchor);
439: } catch (ClassNotFoundException ex) {
440: log
441: .warn("Did not find corresponding java class: "
442: + className);
443: // fall through
444: }
445: }
446: }
447: } else {
448: // not a registered type for bookmarkable pages; create a link
449: // to a resource instead
450: return newPackageResourceReferenceAutoComponent(
451: container, autoId, pathInfo, attribute);
452: }
453:
454: // fallthrough
455: return null;
456: }
457: }
458:
459: /**
460: * Autolink components delegate component resolution to their parent
461: * components. Reason: autolink tags don't have wicket:id and users wouldn't
462: * know where to add the component to.
463: *
464: * @author Juergen Donnerstag
465: */
466: private final static class AutolinkExternalLink extends
467: ExternalLink {
468: private static final long serialVersionUID = 1L;
469:
470: /**
471: * Construct
472: *
473: * @param id
474: * @param href
475: */
476: public AutolinkExternalLink(final String id, final String href) {
477: super (id, href);
478: }
479:
480: /**
481: * @see org.apache.wicket.MarkupContainer#isTransparentResolver()
482: */
483: public boolean isTransparentResolver() {
484: return true;
485: }
486: }
487:
488: /**
489: * Resolver that returns the proper attribute value from a component tag
490: * reflecting a URL reference such as src or href.
491: */
492: private static interface ITagReferenceResolver {
493: /**
494: * Gets the reference attribute value of the tag depending on the type
495: * of the tag. For instance, anchors use the <code>href</code>
496: * attribute but script and image references use the <code>src</code>
497: * attribute.
498: *
499: * @param tag
500: * The component tag. Not for modifcation.
501: * @return the tag value that constitutes the reference
502: */
503: String getReference(final ComponentTag tag);
504: }
505:
506: /**
507: * Autolink component that points to a {@link ResourceReference}. Autolink
508: * component delegate component resolution to their parent components.
509: * Reason: autolink tags don't have wicket:id and users wouldn't know where
510: * to add the component to.
511: */
512: private final static class ResourceReferenceAutolink extends
513: WebMarkupContainer {
514: private static final long serialVersionUID = 1L;
515:
516: private final String attribute;
517:
518: /** Resource reference */
519: private final ResourceReference resourceReference;
520:
521: /**
522: * @param id
523: * @param clazz
524: * @param href
525: * @param attribute
526: */
527: public ResourceReferenceAutolink(final String id,
528: final Class clazz, final String href,
529: final String attribute) {
530: super (id);
531:
532: this .attribute = attribute;
533: // Check whether it is a valid resource reference
534: if (PackageResource.exists(clazz, href, getLocale(),
535: getStyle())) {
536: // Create the component implementing the link
537: resourceReference = new ResourceReference(clazz, href,
538: getLocale(), getStyle());
539: } else {
540: // The resource does not exist. Set to null and ignore when
541: // rendering.
542: resourceReference = null;
543: }
544: }
545:
546: /**
547: * @see org.apache.wicket.MarkupContainer#isTransparentResolver()
548: */
549: public boolean isTransparentResolver() {
550: return true;
551: }
552:
553: /**
554: * Handles this link's tag.
555: *
556: * @param tag
557: * the component tag
558: * @see org.apache.wicket.Component#onComponentTag(ComponentTag)
559: */
560: protected final void onComponentTag(final ComponentTag tag) {
561: // Default handling for tag
562: super .onComponentTag(tag);
563:
564: // only set the href attribute when the resource exists
565: if (resourceReference != null) {
566: // Set href to link to this link's linkClicked method
567: CharSequence url = getRequestCycle().urlFor(
568: resourceReference);
569:
570: // generate the href attribute
571: tag.put(attribute, Strings
572: .replaceAll(url, "&", "&"));
573: }
574: }
575: }
576:
577: /**
578: * Resolves to {@link ResourceReference} link components. Typcically used
579: * for header contributions like javascript and css files.
580: */
581: private static final class ResourceReferenceResolverDelegate extends
582: AbstractAutolinkResolverDelegate {
583: private final String attribute;
584:
585: /**
586: * Construct.
587: *
588: * @param attribute
589: */
590: public ResourceReferenceResolverDelegate(final String attribute) {
591: this .attribute = attribute;
592: }
593:
594: /**
595: * @see org.apache.wicket.markup.resolver.AutoLinkResolver.IAutolinkResolverDelegate#newAutoComponent(org.apache.wicket.MarkupContainer,
596: * java.lang.String,
597: * org.apache.wicket.markup.resolver.AutoLinkResolver.PathInfo)
598: */
599: public Component newAutoComponent(
600: final MarkupContainer container, final String autoId,
601: final PathInfo pathInfo) {
602: return newPackageResourceReferenceAutoComponent(container,
603: autoId, pathInfo, attribute);
604: }
605: }
606:
607: /**
608: * Resolver object that returns the proper attribute value from component
609: * tags.
610: */
611: private static final class TagReferenceResolver implements
612: ITagReferenceResolver {
613: /** the attribute to fetch. */
614: private final String attribute;
615:
616: /**
617: * Construct.
618: *
619: * @param attribute
620: * the attribute to fetch
621: */
622: public TagReferenceResolver(final String attribute) {
623: this .attribute = attribute;
624: }
625:
626: /**
627: * Gets the reference attribute value of the tag depending on the type
628: * of the tag. For instance, anchors use the <code>href</code>
629: * attribute but script and image references use the <code>src</code>
630: * attribute.
631: *
632: * @param tag
633: * The component tag. Not for modifcation.
634: * @return the tag value that constitutes the reference
635: */
636: public String getReference(final ComponentTag tag) {
637: return tag.getAttributes().getString(attribute);
638: }
639: }
640:
641: /**
642: * If no specific resolver is found, always use the href attribute for
643: * references.
644: */
645: private static final TagReferenceResolver DEFAULT_ATTRIBUTE_RESOLVER = new TagReferenceResolver(
646: "href");
647:
648: /** Logging */
649: private static final Logger log = LoggerFactory
650: .getLogger(AutoLinkResolver.class);
651:
652: private static final long serialVersionUID = 1L;
653:
654: /**
655: * Autolink resolver delegates for constructing new autolinks reference
656: * keyed on tag name (such as <script> or <a>.
657: */
658: private final Map tagNameToAutolinkResolverDelegates = new HashMap();
659:
660: /**
661: * Resolver objects that know what attribute to read for getting the
662: * reference keyed on tag name (such as <script> or <a>.
663: */
664: private final Map tagNameToTagReferenceResolvers = new HashMap();
665:
666: /**
667: * Construct.
668: */
669: public AutoLinkResolver() {
670: // register tag reference resolvers
671: TagReferenceResolver hrefTagReferenceResolver = new TagReferenceResolver(
672: "href");
673: TagReferenceResolver srcTagReferenceResolver = new TagReferenceResolver(
674: "src");
675: tagNameToTagReferenceResolvers.put("a",
676: hrefTagReferenceResolver);
677: tagNameToTagReferenceResolvers.put("link",
678: hrefTagReferenceResolver);
679: tagNameToTagReferenceResolvers.put("script",
680: srcTagReferenceResolver);
681: tagNameToTagReferenceResolvers.put("img",
682: srcTagReferenceResolver);
683:
684: // register autolink resolver delegates
685: tagNameToAutolinkResolverDelegates.put("a",
686: new AnchorResolverDelegate());
687: tagNameToAutolinkResolverDelegates.put("link",
688: new ResourceReferenceResolverDelegate("href"));
689: tagNameToAutolinkResolverDelegates.put("script",
690: new ResourceReferenceResolverDelegate("src"));
691: tagNameToAutolinkResolverDelegates.put("img",
692: new ResourceReferenceResolverDelegate("src"));
693: }
694:
695: /**
696: * Register (add or replace) a new resolver with the tagName and
697: * attributeName. The resolver will be invoked each time an appropriate tag
698: * and attribute is found.
699: *
700: * @param tagName
701: * The tag name
702: * @param attributeName
703: * The attribute name
704: * @param resolver
705: * Implements what to do based on the tag and the attribute
706: */
707: public final void addTagReferenceResolver(final String tagName,
708: final String attributeName,
709: final IAutolinkResolverDelegate resolver) {
710: TagReferenceResolver tagReferenceResolver = new TagReferenceResolver(
711: attributeName);
712: tagNameToTagReferenceResolvers.put(tagName,
713: tagReferenceResolver);
714:
715: tagNameToAutolinkResolverDelegates.put(tagName, resolver);
716: }
717:
718: /**
719: * Get the resolver registered for 'tagName'
720: *
721: * @param tagName
722: * The tag's name
723: * @return The resolver found. Null, if none registered
724: */
725: public final IAutolinkResolverDelegate getAutolinkResolverDelegate(
726: final String tagName) {
727: return (IAutolinkResolverDelegate) tagNameToAutolinkResolverDelegates
728: .get(tagName);
729: }
730:
731: /**
732: * Automatically creates a BookmarkablePageLink component.
733: *
734: * @see org.apache.wicket.markup.resolver.IComponentResolver#resolve(MarkupContainer,
735: * MarkupStream, ComponentTag)
736: *
737: * @param markupStream
738: * The current markupStream
739: * @param tag
740: * The current component tag while parsing the markup
741: * @param container
742: * The container parsing its markup
743: * @return true, if componentId was handle by the resolver. False, otherwise
744: */
745: public final boolean resolve(final MarkupContainer container,
746: final MarkupStream markupStream, final ComponentTag tag) {
747: // Must be marked as autolink tag
748: if (tag.isAutolinkEnabled()) {
749: // Try to find the Page matching the href
750: // Note: to not use tag.getId() because it will be modified while
751: // resolving the link and hence the 2nd render will fail.
752: final Component link = resolveAutomaticLink(container,
753: WicketLinkTagHandler.AUTOLINK_ID, tag);
754:
755: // Add the link to the container
756: container.autoAdd(link, markupStream);
757: if (log.isDebugEnabled()) {
758: log.debug("Added autolink " + link);
759: }
760:
761: // Tell the container, we resolved the id
762: return true;
763: }
764:
765: // We were not able to resolve the id
766: return false;
767: }
768:
769: /**
770: * Resolves the given tag's page class and page parameters by parsing the
771: * tag component name and then searching for a page class at the absolute or
772: * relative URL specified by the href attribute of the tag.
773: * <p>
774: * None html references are treated similar.
775: *
776: * @param container
777: * The container where the link is
778: * @param id
779: * the name of the component
780: * @param tag
781: * the component tag
782: * @return A BookmarkablePageLink to handle the href
783: */
784: private final Component resolveAutomaticLink(
785: final MarkupContainer container, final String id,
786: final ComponentTag tag) {
787: final Page page = container.getPage();
788:
789: // Make the id (page-)unique
790: final String autoId = id
791: + Integer.toString(page.getAutoIndex());
792:
793: // get the tag name, which is something like 'a' or 'script'
794: final String tagName = tag.getName();
795:
796: // By setting the component name, the tag becomes a Wicket component
797: // tag, which must have a associated Component.
798: if (tag.getId() == null) {
799: tag.setId(autoId);
800: tag.setAutoComponentTag(true);
801: }
802:
803: // get the reference resolver
804: ITagReferenceResolver referenceResolver = (ITagReferenceResolver) tagNameToTagReferenceResolvers
805: .get(tagName);
806: if (referenceResolver == null) {
807: // fallback on default
808: referenceResolver = DEFAULT_ATTRIBUTE_RESOLVER;
809: }
810:
811: // get the reference, which is typically the value of e.g. a href or src
812: // attribute
813: String reference = referenceResolver.getReference(tag);
814:
815: // create the path info object
816: PathInfo pathInfo = new PathInfo(reference);
817: // now get the resolver delegate
818: IAutolinkResolverDelegate autolinkResolverDelegate = (IAutolinkResolverDelegate) tagNameToAutolinkResolverDelegates
819: .get(tagName);
820: Component autoComponent = null;
821: if (autolinkResolverDelegate != null) {
822: autoComponent = autolinkResolverDelegate.newAutoComponent(
823: container, autoId, pathInfo);
824: }
825:
826: if (autoComponent == null) {
827: // resolving didn't have the desired result or there was no delegate
828: // found; fallback on the default resolving which is a simple
829: // component that leaves the tag unchanged
830: autoComponent = new AutolinkExternalLink(autoId,
831: pathInfo.reference);
832: }
833:
834: return autoComponent;
835: }
836: }
|