001: /*
002: * Title: BaseFactory
003: * Description:
004: *
005: * This software is published under the terms of the OpenSymphony Software
006: * License version 1.1, of which a copy has been included with this
007: * distribution in the LICENSE.txt file.
008: */
009:
010: package com.opensymphony.module.sitemesh.factory;
011:
012: import com.opensymphony.module.sitemesh.Config;
013: import com.opensymphony.module.sitemesh.DecoratorMapper;
014: import com.opensymphony.module.sitemesh.Factory;
015: import com.opensymphony.module.sitemesh.PageParser;
016: import com.opensymphony.module.sitemesh.util.ClassLoaderUtil;
017: import com.opensymphony.module.sitemesh.mapper.PathMapper;
018:
019: import java.util.HashMap;
020: import java.util.Map;
021: import java.util.Properties;
022:
023: /**
024: * Base Factory implementation. Provides utility methods for implementation.
025: *
026: * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
027: * @version $Revision: 1.9 $
028: */
029: public abstract class BaseFactory extends Factory {
030: /** ServletConfig or FilterConfig. */
031: protected Config config = null;
032:
033: /**
034: * Instance of {@link com.opensymphony.module.sitemesh.DecoratorMapper}.
035: * Because it is thread-safe, it can be shared by multiple clients. This
036: * is only the last DecoratorMapper in the chain, and all parents will be
037: * automatically delegated to it.
038: */
039: protected DecoratorMapper decoratorMapper = null;
040:
041: /** Map that associates content-types with PageParser instances. */
042: protected Map pageParsers = null;
043:
044: /** A map of paths that are excluded from decoration */
045: protected PathMapper excludeUrls = null;
046:
047: /**
048: * Constructor for default implementation of Factory.
049: * Should never be called by client. Singleton instance should be
050: * obtained instead.
051: *
052: * @see #getInstance(com.opensymphony.module.sitemesh.Config config)
053: */
054: protected BaseFactory(Config config) {
055: this .config = config;
056: clearDecoratorMappers();
057: clearParserMappings();
058: clearExcludeUrls();
059: }
060:
061: /** Return instance of DecoratorMapper. */
062: public DecoratorMapper getDecoratorMapper() {
063: return decoratorMapper;
064: }
065:
066: /**
067: * Create a PageParser suitable for the given content-type.
068: *
069: * <p>For example, if the supplied parameter is <code>text/html</code>
070: * a parser shall be returned that can parse HTML accordingly. Returns
071: * null if no parser can be found for the supplied content type.</p>
072: *
073: * @param contentType The MIME content-type of the data to be parsed
074: * @return Appropriate <code>PageParser</code> for reading data, or
075: * <code>null</code> if no suitable parser was found.
076: */
077: public PageParser getPageParser(String contentType) {
078: return (PageParser) pageParsers.get(contentType);
079: }
080:
081: /**
082: * Determine whether a Page of given content-type should be parsed or not.
083: */
084: public boolean shouldParsePage(String contentType) {
085: return pageParsers.containsKey(contentType);
086: }
087:
088: /**
089: * Returns <code>true</code> if the supplied path matches one of the exclude
090: * URLs specified in sitemesh.xml, otherwise returns <code>false</code>.
091: * @param path
092: * @return whether the path is excluded
093: */
094: public boolean isPathExcluded(String path) {
095: return excludeUrls.get(path) != null;
096: }
097:
098: /**
099: * Clear all current DecoratorMappers.
100: */
101: protected void clearDecoratorMappers() {
102: decoratorMapper = null;
103: }
104:
105: /** Push new DecoratorMapper onto end of chain. */
106: protected void pushDecoratorMapper(String className,
107: Properties properties) {
108: try {
109: Class decoratorMapperClass = ClassLoaderUtil.loadClass(
110: className, getClass());
111: DecoratorMapper newMapper = getDecoratorMapper(decoratorMapperClass);
112: newMapper.init(config, properties, decoratorMapper);
113: decoratorMapper = newMapper;
114: } catch (ClassNotFoundException e) {
115: throw new FactoryException(
116: "Could not load DecoratorMapper class : "
117: + className, e);
118: } catch (Exception e) {
119: throw new FactoryException(
120: "Could not initialize DecoratorMapper : "
121: + className, e);
122: }
123: }
124:
125: protected DecoratorMapper getDecoratorMapper(
126: Class decoratorMapperClass) throws InstantiationException,
127: IllegalAccessException {
128: return (DecoratorMapper) decoratorMapperClass.newInstance();
129: }
130:
131: /** Clear all PageParser mappings. */
132: protected void clearParserMappings() {
133: pageParsers = new HashMap();
134: }
135:
136: /**
137: * Map new PageParser to given content-type. contentType = null signifies default
138: * PageParser for unknown content-types.
139: */
140: protected void mapParser(String contentType, String className) {
141: if (className.endsWith(".DefaultPageParser")) {
142: return; // Backwards compatability - this can safely be ignored.
143: }
144: try {
145: PageParser pp = (PageParser) ClassLoaderUtil.loadClass(
146: className, getClass()).newInstance();
147: // Store the parser even if the content type is NULL. [This
148: // is most probably the legacy default page parser which
149: // we no longer have a use for]
150: pageParsers.put(contentType, pp);
151: } catch (ClassNotFoundException e) {
152: throw new FactoryException(
153: "Could not load PageParser class : " + className, e);
154: } catch (Exception e) {
155: throw new FactoryException(
156: "Could not instantiate PageParser : " + className,
157: e);
158: }
159: }
160:
161: protected void addExcludeUrl(String path) {
162: excludeUrls.put("", path);
163: }
164:
165: /**
166: * Clears all exclude URLs.
167: */
168: protected void clearExcludeUrls() {
169: excludeUrls = new PathMapper();
170: }
171:
172: }
|