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.component.ComponentManager;
20 import org.apache.avalon.framework.component.Composable;
21 import org.apache.avalon.framework.logger.Logger;
22
23 import org.apache.cocoon.ConnectionResetException;
24 import org.apache.cocoon.ResourceNotFoundException;
25 import org.apache.cocoon.components.treeprocessor.AbstractParentProcessingNode;
26 import org.apache.cocoon.components.treeprocessor.InvokeContext;
27 import org.apache.cocoon.components.treeprocessor.ParameterizableProcessingNode;
28 import org.apache.cocoon.components.treeprocessor.ProcessingNode;
29 import org.apache.cocoon.environment.Environment;
30 import org.apache.cocoon.sitemap.SitemapErrorHandler;
31
32 import java.util.Map;
33
34 /**
35 * Handles <map:pipeline>
36 *
37 * @author <a href="mailto:juergen.seitz@basf-it-services.com">Jürgen Seitz</a>
38 * @author <a href="mailto:bluetkemeier@s-und-n.de">Björn Lütkemeier</a>
39 * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
40 * @author <a href="mailto:gianugo@apache.org">Gianugo Rabellino</a>
41 * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
42 * @version $Id: PipelineNode.java 433543 2006-08-22 06:22:54Z crossley $
43 */
44 public class PipelineNode extends AbstractParentProcessingNode
45 implements Composable, ParameterizableProcessingNode {
46
47 // TODO: handle a 'fail-hard' environment attribute
48 // can be useful to stop off-line generation when there's an error
49
50 private ProcessingNode[] children;
51
52 private ErrorHandlerHelper errorHandlerHelper;
53
54 private boolean internalOnly;
55
56 /** Is it the last <pipeline> in the enclosing <pipelines> ? */
57 private boolean isLast;
58
59 /** The component name of the processing pipeline */
60 protected String processingPipeline;
61
62 /** Optional sitemap parameters */
63 protected Map parameters;
64
65 /**
66 * A constructor to receive the optional expires parameter
67 * and optional parameters for the processing pipeline
68 */
69 public PipelineNode(String name) {
70 this.processingPipeline = name;
71 this.errorHandlerHelper = new ErrorHandlerHelper();
72 }
73
74 /**
75 * The component manager is used to create error pipelines
76 */
77 public void compose(ComponentManager manager) {
78 this.errorHandlerHelper.compose(manager);
79 }
80
81 public void enableLogging(Logger logger) {
82 super.enableLogging(logger);
83 this.errorHandlerHelper.enableLogging(logger);
84 }
85
86 public void setChildren(ProcessingNode[] nodes) {
87 this.children = nodes;
88 }
89
90 public void setParameters(Map parameterMap) {
91 this.parameters = parameterMap;
92 }
93
94 public void setLast(boolean isLast) {
95 this.isLast = isLast;
96 }
97
98 public void set404Handler(ProcessingNode node) {
99 this.errorHandlerHelper.set404Handler(node);
100 }
101
102 public void set500Handler(ProcessingNode node) {
103 this.errorHandlerHelper.set500Handler(node);
104 }
105
106 public void setInternalOnly(boolean internalOnly) {
107 this.internalOnly = internalOnly;
108 }
109
110 public final boolean invoke(Environment env, InvokeContext context)
111 throws Exception {
112 boolean passThrough;
113 Object passThroughRaw = env.getAttribute(MountNode.COCOON_PASS_THROUGH);
114 if (passThroughRaw == null) {
115 // Use default value
116 passThrough = false;
117 } else {
118 passThrough = ((Boolean) passThroughRaw).booleanValue();
119 }
120
121 // Always fail on external request if pipeline is internal only.
122 if (this.internalOnly && env.isExternal()) {
123 if (!this.isLast || passThrough) {
124 return false;
125 }
126
127 // Do not use internal-only pipeline error handler for external requests.
128 throw new ResourceNotFoundException("No pipeline matched request: " +
129 env.getURIPrefix() + env.getURI());
130 }
131
132 context.inform(this.processingPipeline, this.parameters, env.getObjectModel());
133 try {
134 if (this.errorHandlerHelper.isInternal()) {
135 // Set internal error handler in the pipeline
136 context.setErrorHandler(
137 new SitemapErrorHandler(this.errorHandlerHelper, env, context));
138 } else {
139 // Reset internal error handler (previous pipeline might had set it)
140 context.setErrorHandler(null);
141 }
142
143 if (invokeNodes(children, env, context)) {
144 return true;
145 } else if (!this.isLast || passThrough) {
146 return false;
147 }
148
149 throw new ResourceNotFoundException("No pipeline matched request: " +
150 env.getURIPrefix() + env.getURI());
151
152 } catch (ConnectionResetException e) {
153 // Will be reported by CocoonServlet, rethrowing
154 throw e;
155 } catch (Exception e) {
156 // Invoke error handler
157 return this.errorHandlerHelper.invokeErrorHandler(e, env, context);
158 }
159 }
160 }