1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.cocoon.components.treeprocessor.sitemap;
18
19 import org.apache.avalon.framework.activity.Disposable;
20 import org.apache.avalon.framework.component.ComponentException;
21 import org.apache.avalon.framework.component.ComponentManager;
22 import org.apache.avalon.framework.component.ComponentSelector;
23 import org.apache.avalon.framework.component.Composable;
24 import org.apache.avalon.framework.parameters.Parameters;
25 import org.apache.avalon.framework.thread.ThreadSafe;
26 import org.apache.cocoon.components.treeprocessor.InvokeContext;
27 import org.apache.cocoon.components.treeprocessor.ParameterizableProcessingNode;
28 import org.apache.cocoon.components.treeprocessor.SimpleSelectorProcessingNode;
29 import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
30 import org.apache.cocoon.environment.Environment;
31 import org.apache.cocoon.matching.Matcher;
32 import org.apache.cocoon.matching.PreparableMatcher;
33 import org.apache.cocoon.sitemap.PatternException;
34
35 import java.util.Map;
36
37 /**
38 *
39 * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
40 * @version CVS $Id: PreparableMatchNode.java 433543 2006-08-22 06:22:54Z crossley $
41 */
42 public class PreparableMatchNode extends SimpleSelectorProcessingNode
43 implements ParameterizableProcessingNode, Composable, Disposable {
44
45 /** The 'pattern' attribute */
46 private String pattern;
47
48 /** The 'name' for the variable anchor */
49 private String name;
50
51 private Object preparedPattern;
52
53 private Map parameters;
54
55 /** The matcher, if it's ThreadSafe */
56 private PreparableMatcher threadSafeMatcher;
57
58 protected ComponentManager manager;
59
60 public PreparableMatchNode(String type, String pattern, String name) throws PatternException {
61 super(type);
62 this.pattern = pattern;
63 this.name = name;
64 }
65
66 public void setParameters(Map parameterMap) {
67 this.parameters = parameterMap;
68 }
69
70
71 public void compose(ComponentManager manager) throws ComponentException {
72 this.manager = manager;
73 setSelector((ComponentSelector)manager.lookup(Matcher.ROLE + "Selector"));
74
75 // Prepare the pattern, and keep matcher if ThreadSafe
76 PreparableMatcher matcher = (PreparableMatcher)selector.select(componentName);
77
78 if (matcher instanceof ThreadSafe) {
79 this.threadSafeMatcher = matcher;
80 }
81
82 try {
83 this.preparedPattern = matcher.preparePattern(this.pattern);
84
85 } catch(PatternException pe) {
86 String msg = "Invalid pattern '" + this.pattern + "' for matcher at " + this.getLocation();
87 throw new ComponentException(null, msg, pe);
88
89 } finally {
90 if (this.threadSafeMatcher == null) {
91 selector.release(matcher);
92 }
93 }
94 }
95
96 public final boolean invoke(Environment env, InvokeContext context)
97 throws Exception {
98
99 // Perform any common invoke functionality
100 super.invoke(env, context);
101
102 Map objectModel = env.getObjectModel();
103 Parameters resolvedParams = VariableResolver.buildParameters(
104 this.parameters, context, objectModel
105 );
106
107 Map result = null;
108
109 if (this.threadSafeMatcher != null) {
110 // Avoid select() and try/catch block (faster !)
111 result = this.threadSafeMatcher.preparedMatch(preparedPattern, objectModel, resolvedParams);
112
113 } else {
114 // Get matcher from selector
115 PreparableMatcher matcher = (PreparableMatcher)this.selector.select(this.componentName);
116 try {
117 result = matcher.preparedMatch(preparedPattern, objectModel, resolvedParams);
118
119 } finally {
120 this.selector.release(matcher);
121 }
122 }
123
124 if (result != null) {
125 if (getLogger().isDebugEnabled()) {
126 getLogger().debug("Matcher '" + this.componentName + "' matched prepared pattern '" +
127 this.pattern + "' at " + this.getLocation());
128 }
129
130 // Invoke children with the matcher results
131 return this.invokeNodes(children, env, context, name, result);
132
133 } else {
134 // Matcher failed
135 return false;
136 }
137 }
138
139 /**
140 * Disposable Interface
141 */
142 public void dispose() {
143 if (this.threadSafeMatcher != null) {
144 selector.release(this.threadSafeMatcher);
145 this.threadSafeMatcher = null;
146 }
147 if (this.selector != null) {
148 this.manager.release(this.selector);
149 this.selector = null;
150 }
151 this.manager = null;
152 }
153 }