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.cocoon.components.treeprocessor.sitemap;
018:
019: import org.apache.avalon.framework.activity.Disposable;
020: import org.apache.avalon.framework.component.ComponentException;
021: import org.apache.avalon.framework.component.ComponentManager;
022: import org.apache.avalon.framework.component.ComponentSelector;
023: import org.apache.avalon.framework.component.Composable;
024: import org.apache.avalon.framework.parameters.Parameters;
025: import org.apache.avalon.framework.thread.ThreadSafe;
026: import org.apache.cocoon.components.treeprocessor.InvokeContext;
027: import org.apache.cocoon.components.treeprocessor.ParameterizableProcessingNode;
028: import org.apache.cocoon.components.treeprocessor.SimpleSelectorProcessingNode;
029: import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
030: import org.apache.cocoon.environment.Environment;
031: import org.apache.cocoon.matching.Matcher;
032: import org.apache.cocoon.matching.PreparableMatcher;
033: import org.apache.cocoon.sitemap.PatternException;
034:
035: import java.util.Map;
036:
037: /**
038: *
039: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
040: * @version CVS $Id: PreparableMatchNode.java 433543 2006-08-22 06:22:54Z crossley $
041: */
042: public class PreparableMatchNode extends SimpleSelectorProcessingNode
043: implements ParameterizableProcessingNode, Composable,
044: Disposable {
045:
046: /** The 'pattern' attribute */
047: private String pattern;
048:
049: /** The 'name' for the variable anchor */
050: private String name;
051:
052: private Object preparedPattern;
053:
054: private Map parameters;
055:
056: /** The matcher, if it's ThreadSafe */
057: private PreparableMatcher threadSafeMatcher;
058:
059: protected ComponentManager manager;
060:
061: public PreparableMatchNode(String type, String pattern, String name)
062: throws PatternException {
063: super (type);
064: this .pattern = pattern;
065: this .name = name;
066: }
067:
068: public void setParameters(Map parameterMap) {
069: this .parameters = parameterMap;
070: }
071:
072: public void compose(ComponentManager manager)
073: throws ComponentException {
074: this .manager = manager;
075: setSelector((ComponentSelector) manager.lookup(Matcher.ROLE
076: + "Selector"));
077:
078: // Prepare the pattern, and keep matcher if ThreadSafe
079: PreparableMatcher matcher = (PreparableMatcher) selector
080: .select(componentName);
081:
082: if (matcher instanceof ThreadSafe) {
083: this .threadSafeMatcher = matcher;
084: }
085:
086: try {
087: this .preparedPattern = matcher.preparePattern(this .pattern);
088:
089: } catch (PatternException pe) {
090: String msg = "Invalid pattern '" + this .pattern
091: + "' for matcher at " + this .getLocation();
092: throw new ComponentException(null, msg, pe);
093:
094: } finally {
095: if (this .threadSafeMatcher == null) {
096: selector.release(matcher);
097: }
098: }
099: }
100:
101: public final boolean invoke(Environment env, InvokeContext context)
102: throws Exception {
103:
104: // Perform any common invoke functionality
105: super .invoke(env, context);
106:
107: Map objectModel = env.getObjectModel();
108: Parameters resolvedParams = VariableResolver.buildParameters(
109: this .parameters, context, objectModel);
110:
111: Map result = null;
112:
113: if (this .threadSafeMatcher != null) {
114: // Avoid select() and try/catch block (faster !)
115: result = this .threadSafeMatcher.preparedMatch(
116: preparedPattern, objectModel, resolvedParams);
117:
118: } else {
119: // Get matcher from selector
120: PreparableMatcher matcher = (PreparableMatcher) this .selector
121: .select(this .componentName);
122: try {
123: result = matcher.preparedMatch(preparedPattern,
124: objectModel, resolvedParams);
125:
126: } finally {
127: this .selector.release(matcher);
128: }
129: }
130:
131: if (result != null) {
132: if (getLogger().isDebugEnabled()) {
133: getLogger().debug(
134: "Matcher '" + this .componentName
135: + "' matched prepared pattern '"
136: + this .pattern + "' at "
137: + this .getLocation());
138: }
139:
140: // Invoke children with the matcher results
141: return this .invokeNodes(children, env, context, name,
142: result);
143:
144: } else {
145: // Matcher failed
146: return false;
147: }
148: }
149:
150: /**
151: * Disposable Interface
152: */
153: public void dispose() {
154: if (this.threadSafeMatcher != null) {
155: selector.release(this.threadSafeMatcher);
156: this.threadSafeMatcher = null;
157: }
158: if (this.selector != null) {
159: this.manager.release(this.selector);
160: this.selector = null;
161: }
162: this.manager = null;
163: }
164: }
|