001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.frontend;
017:
018: import org.apache.cocoon.xml.SaxBuffer;
019: import org.apache.cocoon.components.flow.util.PipelineUtil;
020: import org.apache.cocoon.components.LifecycleHelper;
021: import org.apache.avalon.framework.context.Context;
022: import org.apache.avalon.framework.service.ServiceManager;
023: import org.outerj.daisy.repository.Repository;
024: import org.outerj.daisy.repository.VariantKey;
025: import org.outerj.daisy.util.Constants;
026: import org.outerj.daisy.frontend.components.siteconf.SiteConf;
027:
028: import java.util.Map;
029: import java.util.HashMap;
030: import java.util.List;
031:
032: /**
033: * This class is concerned with applying document type specific styling (by using
034: * Cocoon pipelines) to the documents stored in a {@link PreparedDocuments} object.
035: */
036: public class DocumentTypeSpecificStyler {
037: private final String publishType;
038: private final String basePath;
039: private final String daisyCocoonPath;
040: private final StylesheetProvider stylesheetProvider;
041: private final PageContext pageContext;
042: private final Repository repository;
043: private final Context context;
044: private final ServiceManager serviceManager;
045:
046: /**
047: *
048: * @param publishType 'html' or 'xslfo' or anything for which a pipeline is defined
049: * @param basePath the base path for addressing documents (should end on a slash).
050: * This is simply passed as a parameter to the stylesheets, who can use it if they need.
051: * @param stylesheetProvider
052: */
053: public DocumentTypeSpecificStyler(String publishType,
054: String basePath, String daisyCocoonPath,
055: StylesheetProvider stylesheetProvider,
056: PageContext pageContext, Repository repository,
057: Context context, ServiceManager serviceManager) {
058: this .publishType = publishType;
059: this .basePath = basePath;
060: this .daisyCocoonPath = daisyCocoonPath;
061: this .stylesheetProvider = stylesheetProvider;
062: this .repository = repository;
063: this .context = context;
064: this .serviceManager = serviceManager;
065: this .pageContext = pageContext;
066: }
067:
068: public static interface StylesheetProvider {
069: String getStylesheet(String documentTypeName) throws Exception;
070:
071: String getDefaultStylesheet() throws Exception;
072:
073: String getStylesheetByHint(String styleHint) throws Exception;
074: }
075:
076: public void transformPreparedDocuments(
077: PreparedDocuments preparedDocuments, String displayContext)
078: throws Exception {
079: int[] ids = preparedDocuments.getPreparedDocumentIds();
080: for (int id : ids) {
081: PreparedDocuments.PreparedDocument preparedDocument = preparedDocuments
082: .getPreparedDocument(id);
083: SaxBuffer buffer = preparedDocument.getSaxBuffer();
084:
085: Object styleInfo = searchStyleInfo(buffer);
086: String stylesheet;
087: if (styleInfo != null) {
088: if (styleInfo instanceof Long) {
089: long documentTypeId = ((Long) styleInfo)
090: .longValue();
091: String documentTypeName = repository
092: .getRepositorySchema().getDocumentTypeById(
093: documentTypeId, false).getName();
094: stylesheet = stylesheetProvider
095: .getStylesheet(documentTypeName);
096: } else {
097: stylesheet = stylesheetProvider
098: .getStylesheetByHint((String) styleInfo);
099: }
100: } else {
101: stylesheet = stylesheetProvider.getDefaultStylesheet();
102: }
103:
104: // Calculate variantQueryString and variantParams (supplied to stylesheets for convenience)
105: VariantKey documentKey = preparedDocument.getDocumentKey();
106: SiteConf siteConf = pageContext.getSiteConf();
107: String variantParams = "";
108: String variantQueryString = "";
109: if (documentKey.getBranchId() != siteConf.getBranchId()
110: || documentKey.getLanguageId() != siteConf
111: .getLanguageId()) {
112: String branch = repository.getVariantManager()
113: .getBranch(documentKey.getBranchId(), false)
114: .getName();
115: String language = repository
116: .getVariantManager()
117: .getLanguage(documentKey.getLanguageId(), false)
118: .getName();
119: variantParams = "&branch=" + branch + "&language="
120: + language;
121: variantQueryString = "?branch=" + branch + "&language="
122: + language;
123: }
124:
125: Map<String, Object> viewData = new HashMap<String, Object>();
126: viewData.put("stylesheet", stylesheet);
127: viewData.put("pageContext", pageContext);
128: viewData.put("repository", repository);
129: viewData.put("document", buffer);
130: viewData.put("documentBasePath", basePath);
131: viewData.put("displayContext",
132: displayContext != null ? displayContext : "");
133: viewData.put("isIncluded", String.valueOf(id != 1)); // root document has ID 1 in prep-docs
134: viewData.put("documentKey", documentKey);
135: viewData
136: .put("documentBranch", repository
137: .getVariantManager().getBranch(
138: documentKey.getBranchId(), false)
139: .getName());
140: viewData.put("documentLanguage", repository
141: .getVariantManager().getLanguage(
142: documentKey.getLanguageId(), false)
143: .getName());
144: viewData.put("variantQueryString", variantQueryString);
145: viewData.put("variantParams", variantParams);
146:
147: SaxBuffer resultBuffer = executePipeline(daisyCocoonPath
148: + "/" + publishType + "-StyleDocumentPipe",
149: viewData);
150: preparedDocuments.putPreparedDocument(preparedDocument
151: .getId(), preparedDocument.getDocumentKey(),
152: resultBuffer);
153: }
154: }
155:
156: /**
157: * Searches the supplied buffer and returns:
158: * <ul>
159: * <li>a String containing the value of the styleHint attribute on the p:publisherResponse element, if found
160: * <li>otherwise a Long containing the typeId attribute of the first d:document element encountered
161: * <li>otherwise null
162: * </ul>
163: *
164: * @param buffer containing the XML of the publisher request for the document.
165: */
166: public static Object searchStyleInfo(SaxBuffer buffer) {
167: List bits = buffer.getBits();
168: boolean publisherResponseElementFound = false;
169: for (Object bit : bits) {
170: if (bit instanceof SaxBuffer.StartElement) {
171: SaxBuffer.StartElement startElement = (SaxBuffer.StartElement) bit;
172: if (!publisherResponseElementFound
173: && startElement.namespaceURI
174: .equals("http://outerx.org/daisy/1.0#publisher")
175: && startElement.localName
176: .equals("publisherResponse")) {
177: String styleHint = startElement.attrs
178: .getValue("styleHint");
179: if (styleHint != null && styleHint.length() != 0)
180: return styleHint;
181: publisherResponseElementFound = true;
182: } else if (startElement.namespaceURI
183: .equals(Constants.DAISY_NAMESPACE)
184: && startElement.localName.equals("document")) {
185: return new Long(Long.parseLong(startElement.attrs
186: .getValue("typeId")));
187: }
188: }
189: }
190: return null;
191: }
192:
193: /**
194: * Executes a Cocoon pipeline and store the result in a SaxBuffer instance.
195: */
196: private SaxBuffer executePipeline(String pipe, Map viewData)
197: throws Exception {
198: PipelineUtil pipelineUtil = new PipelineUtil();
199: try {
200: LifecycleHelper.setupComponent(pipelineUtil, null, context,
201: serviceManager, null, false);
202:
203: SaxBuffer buffer = new SaxBuffer();
204: pipelineUtil.processToSAX(pipe, viewData, buffer);
205:
206: return buffer;
207: } finally {
208: LifecycleHelper.dispose(pipelineUtil);
209: }
210: }
211: }
|