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.parameters.Parameters;
020:
021: import org.apache.cocoon.components.pipeline.ProcessingPipeline;
022: import org.apache.cocoon.components.treeprocessor.AbstractProcessingNode;
023: import org.apache.cocoon.components.treeprocessor.InvokeContext;
024: import org.apache.cocoon.components.treeprocessor.ProcessingNode;
025: import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
026: import org.apache.cocoon.environment.Environment;
027: import org.apache.cocoon.sitemap.ContentAggregator;
028:
029: import java.util.Map;
030:
031: /**
032: * Aggregate sitemap node.
033: *
034: * <h3>View handling in aggregation</h3>
035: * <ul>
036: * <li>map:aggregate can have a label, but doesn't match view from-position="first" like generators
037: * </li>
038: * <li>each map:part can have a label
039: * </li>
040: * <li>if at least one of the parts has a label matching the current view, only parts matching
041: * this view are added. Otherwise, all parts are added.
042: * </li>
043: * </ul>
044: * For more info on aggregation and views, see the mail archive
045: * <a href="http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=100525751417953">here</a> or
046: * <a href="http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=100517130418424">here</a>.
047: *
048: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
049: * @version $Id: AggregateNode.java 433543 2006-08-22 06:22:54Z crossley $
050: */
051: public class AggregateNode extends AbstractProcessingNode {
052:
053: private VariableResolver element;
054: private VariableResolver nsURI;
055: private VariableResolver nsPrefix;
056:
057: /** All parts */
058: private Part[] allParts;
059:
060: /** Pre-filtered Part[] for views that have a matching label in any of the parts */
061: private Map viewParts;
062:
063: /** View nodes to jump to */
064: private Map viewNodes;
065:
066: public AggregateNode(VariableResolver element,
067: VariableResolver nsURI, VariableResolver nsPrefix) {
068: this .element = element;
069: this .nsURI = nsURI;
070: this .nsPrefix = nsPrefix;
071: }
072:
073: public void setParts(Part[] allParts, Map viewParts) {
074: this .allParts = allParts;
075: this .viewParts = viewParts;
076: }
077:
078: public void setViewNodes(Map viewNodes) {
079: this .viewNodes = viewNodes;
080: }
081:
082: public boolean invoke(Environment env, InvokeContext context)
083: throws Exception {
084: final boolean infoEnabled = getLogger().isInfoEnabled();
085:
086: Map objectModel = env.getObjectModel();
087:
088: // Setup aggregator
089: ProcessingPipeline processingPipeline = context
090: .getProcessingPipeline();
091: processingPipeline.setGenerator("<aggregator>", null,
092: Parameters.EMPTY_PARAMETERS,
093: Parameters.EMPTY_PARAMETERS);
094:
095: ContentAggregator aggregator = (ContentAggregator) processingPipeline
096: .getGenerator();
097: aggregator.setRootElement(this .element.resolve(context,
098: objectModel), this .nsURI.resolve(context, objectModel),
099: this .nsPrefix.resolve(context, objectModel));
100:
101: // Get actual parts, potentially filtered by the view
102: Part[] actualParts;
103:
104: String cocoonView = env.getView();
105: if (cocoonView == null) {
106: // Keep all parts
107: actualParts = this .allParts;
108:
109: } else {
110: // Are there some parts that match this view ?
111: actualParts = (Part[]) this .viewParts.get(cocoonView);
112:
113: // If not, keep all parts
114: if (actualParts == null) {
115: actualParts = this .allParts;
116: }
117: }
118:
119: // Add parts
120: for (int i = 0; i < actualParts.length; i++) {
121: Part part = actualParts[i];
122: if (part != null) {
123: aggregator.addPart(part.source.resolve(context,
124: objectModel), part.element.resolve(context,
125: objectModel), part.nsURI.resolve(context,
126: objectModel), part.stripRoot.resolve(context,
127: objectModel), part.nsPrefix.resolve(context,
128: objectModel));
129: }
130: }
131:
132: // Bug #7196 : Some parts matched the view: jump to that view
133: if (actualParts != this .allParts) {
134: ProcessingNode viewNode = (ProcessingNode) this .viewNodes
135: .get(cocoonView);
136: if (viewNode != null) {
137: if (infoEnabled) {
138: getLogger().info(
139: "Jumping to view '" + cocoonView
140: + "' from aggregate part at "
141: + this .getLocation());
142: }
143: return viewNode.invoke(env, context);
144: }
145: }
146:
147: // Check aggregate-level view
148: if (cocoonView != null && this .viewNodes != null) {
149: ProcessingNode viewNode = (ProcessingNode) this .viewNodes
150: .get(cocoonView);
151: if (viewNode != null) {
152: if (infoEnabled) {
153: getLogger().info(
154: "Jumping to view '" + cocoonView
155: + "' from aggregate at "
156: + this .getLocation());
157: }
158: return viewNode.invoke(env, context);
159: }
160: }
161:
162: // Return false to continue sitemap invocation
163: return false;
164: }
165:
166: public static class Part {
167: protected VariableResolver source;
168: protected VariableResolver element;
169: protected VariableResolver nsURI;
170: protected VariableResolver nsPrefix;
171: protected VariableResolver stripRoot;
172:
173: public Part(VariableResolver source, VariableResolver element,
174: VariableResolver nsURI, VariableResolver nsPrefix,
175: VariableResolver stripRoot) {
176: this.source = source;
177: this.element = element;
178: this.nsURI = nsURI;
179: this.nsPrefix = nsPrefix;
180: this.stripRoot = stripRoot;
181: }
182: }
183: }
|