Source code: com/sitemesh/mapper/DefaultDecoratorMapper.java
1 package com.sitemesh.mapper;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.*;
6 import javax.servlet.Config;
7 import javax.servlet.ServletException;
8 import javax.servlet.http.HttpServletRequest;
9 import javax.xml.parsers.DocumentBuilder;
10 import javax.xml.parsers.DocumentBuilderFactory;
11 import javax.xml.parsers.ParserConfigurationException;
12 import org.w3c.dom.*;
13 import org.xml.sax.SAXException;
14 import com.sitemesh.*;
15
16 // ---------------- PLEASE REFACTOR ME!!! --------------------
17
18 /**
19 * Default implementation of DecoratorMapper. Reads decorators and
20 * mappings from <code>/WEB-INF/decorators.xml</code>.
21 *
22 * @author <a href="joe@truemesh.com">Joe Walnes</a>
23 * @author <a href="mcannon@internet.com">Mike Cannon-Brookes</a>
24 * @version $Revision: 1.5 $
25 *
26 * @see com.sitemesh.DecoratorMapper
27 * @see com.sitemesh.mapper.DefaultDecorator
28 */
29 public class DefaultDecoratorMapper implements DecoratorMapper, RequestConstants {
30
31 private Map decorators;
32 private Map mappings;
33 private long configLastModified;
34 private File configFile;
35
36 /**
37 * @label constructs
38 * @directed
39 */
40 /*#private DefaultDecorator lnkDefaultDecorator;*/
41
42 public void init(Config config, Properties properties) throws InstantiationException {
43 try {
44 String fileName = config.getInitParameter("decorators.config");
45 if (fileName == null) fileName = "/WEB-INF/decorators.xml";
46 configFile = new File( config.getServletContext().getRealPath(fileName) );
47 loadConfig();
48 }
49 catch (Exception e) {
50 throw new InstantiationException(e.toString());
51 }
52 }
53
54 public Decorator getDecorator(HttpServletRequest request, Page page) {
55 Decorator result = null;
56 if ( page instanceof HTMLPage ) {
57 // Only try and find a Decorator if instance of HTMLPage
58 if ( request.getAttribute(DECORATOR) != null ) {
59 // Retrieve name of decorator to use from request
60 String decoratorName = (String)request.getAttribute(DECORATOR);
61 result = ( Decorator )decorators.get( decoratorName );
62 }
63 else {
64 // If that doesn't work, get the decorator-mapping for the url.
65 String key = findKey( request.getServletPath() );
66 result = ( Decorator )decorators.get( ( String )mappings.get( key ) );
67 }
68 }
69 return result;
70 }
71
72 private String findKey( String path ) {
73 String result = findExactKey( path );
74 if ( result == null ) result = findDirectoryKey( path );
75 if ( result == null ) result = findExtentionKey( path );
76 if ( result == null ) result = findDefaultKey( path );
77 return result;
78 }
79
80 private String findExactKey( String path ) {
81 if ( mappings.containsKey( path ) ) return path;
82 return null;
83 }
84
85 private String findDirectoryKey( String path ) {
86 if (path.lastIndexOf("/") <= 0) return null;
87 String tempPath = path.substring(0, path.lastIndexOf("/"));
88 while (!tempPath.equals("/") && tempPath.length() > 0) {
89 if ( mappings.containsKey( tempPath + "/*" ) ) return tempPath + "/*";
90 tempPath = tempPath.substring(0, tempPath.lastIndexOf("/"));
91 }
92 return null;
93 }
94
95 private String findExtentionKey( String path ) {
96 if ( path.indexOf( "." ) == -1 ) return null;
97 String ext = path.substring( path.lastIndexOf( "." ) + 1 );
98 String[] extKeys = {"*."+ext , "/*."+ext};
99 for ( int i = 0; i < extKeys.length; i++ ) {
100 if ( mappings.containsKey( extKeys[i] ) ) return extKeys[i];
101 }
102 return null;
103 }
104
105 private String findDefaultKey( String path ) {
106 String[] defaultKeys = {"/","*","/*"};
107 for ( int i = 0; i < defaultKeys.length; i++ ) {
108 if ( mappings.containsKey( defaultKeys[i] ) ) return defaultKeys[i];
109 }
110 return null;
111 }
112
113 private synchronized void loadConfig() throws ServletException {
114 try {
115 // Clear previous config
116 mappings = new HashMap();
117 decorators = new HashMap();
118 // Parse file
119 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
120 DocumentBuilder builder = factory.newDocumentBuilder();
121 configLastModified = configFile.lastModified();
122 Document document = builder.parse( configFile );
123 Element root = document.getDocumentElement();
124 // Verify root element
125 if ( !root.getTagName().equals( "decorators" ) ) {
126 throw new ServletException( "Root element of decorators config file not <decorators>" );
127 }
128 // Get decorators
129 NodeList decoratorNodes = root.getElementsByTagName( "decorator" );
130 for ( int i = 0; i < decoratorNodes.getLength(); i++ ) {
131 String name = getContainedText( decoratorNodes.item( i ), "decorator-name" );
132 String page = getContainedText( decoratorNodes.item( i ), "jsp-file" );
133 Map params = new HashMap();
134 NodeList paramNodes = ( ( Element )decoratorNodes.item( i ) ).getElementsByTagName( "init-param" );
135 for ( int ii = 0; ii < paramNodes.getLength(); ii++ ) {
136 String paramName = getContainedText( paramNodes.item( ii ), "param-name" );
137 String paramValue = getContainedText( paramNodes.item( ii ), "param-value" );
138 params.put( paramName, paramValue );
139 }
140 storeDecorator( new DefaultDecorator( name, page, params ) );
141 }
142 // Get decorator-mappings
143 NodeList mappingNodes = root.getElementsByTagName( "decorator-mapping" );
144 for ( int i = 0; i < mappingNodes.getLength(); i++ ) {
145 Element n = ( Element )mappingNodes.item( i );
146 String name = getContainedText( mappingNodes.item( i ), "decorator-name" );
147 String pattern = getContainedText( mappingNodes.item( i ), "url-pattern" );
148 storeMapping( name, pattern );
149 }
150 }
151 catch ( ParserConfigurationException e ) {
152 throw new ServletException( "Could not get XML parser", e );
153 }
154 catch ( IOException e ) {
155 throw new ServletException( "Could not read config file", e );
156 }
157 catch ( SAXException e ) {
158 throw new ServletException( "Could not parse config file", e );
159 }
160 }
161
162 private String getContainedText( Node parent, String childTagName ) {
163 try {
164 Node tag = ( ( Element )parent ).getElementsByTagName( childTagName ).item( 0 );
165 String text = ( ( Text )tag.getFirstChild() ).getData();
166 return text;
167 }
168 catch ( Exception e ) {
169 return null;
170 }
171 }
172
173 private void storeDecorator( Decorator d ) {
174 decorators.put( d.getName(), d );
175 }
176
177 private void storeMapping( String name, String pattern ) {
178 mappings.put( pattern, name );
179 }
180
181 /** Check if configuration file has been updated, and if so, reload. */
182 public synchronized void refresh() throws ServletException {
183 if (configLastModified != configFile.lastModified()) loadConfig();
184 }
185
186 }