KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > matching > MountTableMatcher


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.matching;
17
18 import org.apache.avalon.framework.configuration.Configuration;
19 import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
20 import org.apache.avalon.framework.logger.AbstractLogEnabled;
21 import org.apache.avalon.framework.parameters.ParameterException;
22 import org.apache.avalon.framework.parameters.Parameterizable;
23 import org.apache.avalon.framework.parameters.Parameters;
24 import org.apache.avalon.framework.service.ServiceException;
25 import org.apache.avalon.framework.service.ServiceManager;
26 import org.apache.avalon.framework.service.Serviceable;
27 import org.apache.avalon.framework.thread.ThreadSafe;
28
29 import org.apache.cocoon.components.source.SourceUtil;
30 import org.apache.cocoon.environment.ObjectModelHelper;
31 import org.apache.cocoon.environment.Request;
32 import org.apache.cocoon.sitemap.PatternException;
33
34 import org.apache.excalibur.source.Source;
35 import org.apache.excalibur.source.SourceResolver;
36 import org.apache.excalibur.source.SourceValidity;
37
38 import java.util.Collections JavaDoc;
39 import java.util.HashMap JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.Map JavaDoc;
42
43 /**
44  * A matcher that manages a "mount table", allowing to add subsitemaps to a Cocoon application without
45  * modifying the main sitemap. This is especially useful for prototypes and demos where installing
46  * a separate instance of Cocoon is overkill.
47  * <p>
48  * The mount table is an xml file which has a format similar to the <code>map:mount</code> syntax:
49  * <pre>
50  * &lt;mount-table&gt;
51  * &lt;mount uri-prefix="foo" SRC="file://path/to/foo/directory/"/&gt;
52  * &lt;mount uri-prefix="bar/baz" SRC="file://path/to/bar-baz/directory/"/&gt;
53  * &lt;/mount-table&gt;
54  * </pre>
55  * The matcher will scan the mount table for an "uri-prefix" value matching the beginning of the current
56  * request URI, and if found, succeed and populate the "src" and "uri-prefix" sitemap variables.
57  * <p>
58  * Usage in the sitemap is therefore as follows:
59  * <pre>
60  * &lt;map:match type="mount-table" pattern="path/to/mount-table.xml"&gt;
61  * &lt;map:mount uri-prefix="{uri-prefix}" SRC="{src}"/&gt;
62  * &lt;/map:match&gt;
63  * </pre>
64  * <p>
65  * This matcher accepts a single configuration parameter, indicating if missing mount tables should be
66  * silently ignored (defaults is <code>false</code>, meaning "don't ignore"):
67  * <pre>
68  * &lt;map:matcher type="mount-table" SRC="org.apache.cocoon.matching.MountTableMatcher"&gt;
69  * &lt;map:parameter name="ignore-missing-tables" value="true"/&gt;
70  * &lt;/map:matcher&gt;
71  * </pre>
72  * <p>
73  * This configuration is used in the main sitemap of Cocoon samples, to allow users to define their own mount
74  * table, but not fail if it does not exist.
75  *
76  * @author <a HREF="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
77  * @version $Id: MountTableMatcher.java 159598 2005-03-31 14:44:00Z vgritsenko $
78  */

79 public class MountTableMatcher extends AbstractLogEnabled
80                                implements Matcher, ThreadSafe, Serviceable, Parameterizable {
81
82     private ServiceManager manager;
83     private SourceResolver resolver;
84     private Map JavaDoc mountTables = Collections.synchronizedMap(new HashMap JavaDoc());
85     private boolean ignoreMissingTables;
86
87     public void service(ServiceManager manager) throws ServiceException {
88         this.manager = manager;
89         this.resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
90     }
91
92     public void parameterize(Parameters params) throws ParameterException {
93         this.ignoreMissingTables = params.getParameterAsBoolean("ignore-missing-tables", false);
94     }
95
96     private Map JavaDoc getMountTable(String JavaDoc src) throws Exception JavaDoc {
97         Source source = null;
98         try {
99             source = this.resolver.resolveURI(src);
100             final String JavaDoc uri = source.getURI();
101
102             // Check if source exists
103
if (!source.exists()) {
104                 if (this.ignoreMissingTables) {
105                     return Collections.EMPTY_MAP;
106                 } else {
107                     throw new PatternException("Mount table does not exist: '" + uri + "'");
108                 }
109             }
110
111             // Source exists
112
Object JavaDoc[] values = (Object JavaDoc[]) this.mountTables.get(uri);
113             if (values != null) {
114                 // Check validity
115
SourceValidity oldValidity = (SourceValidity) values[1];
116
117                 int valid = oldValidity != null ? oldValidity.isValid() : SourceValidity.INVALID;
118                 if (valid == SourceValidity.VALID) {
119                     // Valid without needing the new validity
120
return (Map JavaDoc) values[0];
121                 }
122
123                 if (valid == SourceValidity.UNKNOWN &&
124                         oldValidity.isValid(source.getValidity()) == SourceValidity.VALID) {
125                     // Valid after comparing with the new validity
126
return (Map JavaDoc) values[0];
127                 }
128
129                 // Invalid: fallback below to read the mount table
130
} else {
131                 values = new Object JavaDoc[2];
132             }
133
134             // Read the mount table
135
Map JavaDoc mounts = new HashMap JavaDoc();
136             DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
137             Configuration config = builder.build(SourceUtil.getInputSource(source));
138
139             Configuration[] children = config.getChildren();
140             for (int i = 0; i < children.length; i++) {
141                 Configuration child = children[i];
142                 if ("mount".equals(child.getName())) {
143                     String JavaDoc prefix = children[i].getAttribute("uri-prefix");
144                     // Append a '/' at the end of a not-empty prefix
145
// this avoids flat uri matching which would cause
146
// exceptions in the sub sitemap!
147
if (!prefix.endsWith("/") && prefix.length() != 0) {
148                         prefix = prefix + '/';
149                     }
150                     mounts.put(prefix, children[i].getAttribute("src"));
151                 } else {
152                     throw new PatternException(
153                         "Unexpected element '" + child.getName() + "' (awaiting 'mount'), at " + child.getLocation());
154                 }
155             }
156             values[0] = mounts;
157             values[1] = source.getValidity();
158
159             // Cache it with the source validity
160
this.mountTables.put(uri, values);
161
162             return mounts;
163
164         } catch (SecurityException JavaDoc e) {
165             if (this.ignoreMissingTables) {
166                 return Collections.EMPTY_MAP;
167             } else {
168                 throw new PatternException("Mount table is not accessible: '" + src + "' (" + e + ")");
169             }
170
171         } finally {
172             if (source != null) {
173                 this.resolver.release(source);
174             }
175         }
176     }
177
178     public Map JavaDoc match(String JavaDoc pattern, Map JavaDoc objectModel, Parameters parameters) throws PatternException {
179         Map JavaDoc mounts;
180         try {
181             mounts = getMountTable(pattern);
182         } catch (PatternException pe) {
183             throw pe;
184         } catch (Exception JavaDoc e) {
185             throw new PatternException(e);
186         }
187
188         // Get the request URI
189
Request request = ObjectModelHelper.getRequest(objectModel);
190         String JavaDoc uri = request.getSitemapURI();
191
192         // and search for a matching prefix
193
Iterator JavaDoc iter = mounts.entrySet().iterator();
194         while (iter.hasNext()) {
195             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
196             String JavaDoc prefix = (String JavaDoc) entry.getKey();
197             if (uri.startsWith(prefix)) {
198                 // Found it
199
Map JavaDoc result = new HashMap JavaDoc(2);
200                 result.put("uri-prefix", prefix);
201                 result.put("src", entry.getValue());
202
203                 // Return immediately
204
return result;
205             }
206         }
207
208         // Not found
209
return null;
210     }
211 }
212
Popular Tags