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: */
018:
019: package org.apache.lenya.cms.publication.templating;
020:
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.List;
024:
025: import org.apache.avalon.framework.logger.AbstractLogEnabled;
026: import org.apache.avalon.framework.logger.Logger;
027: import org.apache.avalon.framework.service.ServiceException;
028: import org.apache.avalon.framework.service.ServiceManager;
029: import org.apache.avalon.framework.service.ServiceSelector;
030: import org.apache.avalon.framework.service.Serviceable;
031: import org.apache.excalibur.source.SourceResolver;
032: import org.apache.lenya.cms.publication.Publication;
033: import org.apache.lenya.cms.publication.PublicationException;
034:
035: /**
036: * Manager for publication templates.
037: *
038: * @version $Id: PublicationTemplateManagerImpl.java 474729 2006-11-14 11:07:44Z
039: * andreas $
040: */
041: public class PublicationTemplateManagerImpl extends AbstractLogEnabled
042: implements PublicationTemplateManager, Serviceable {
043:
044: /**
045: * Ctor.
046: */
047: public PublicationTemplateManagerImpl() {
048: }
049:
050: /**
051: * @see org.apache.lenya.cms.publication.templating.PublicationTemplateManager#visit(org.apache.lenya.cms.publication.Publication,
052: * java.lang.String,
053: * org.apache.lenya.cms.publication.templating.SourceVisitor)
054: */
055: public void visit(Publication publication, String path,
056: SourceVisitor visitor) {
057:
058: SourceResolver resolver = null;
059: try {
060: resolver = (SourceResolver) this .manager
061: .lookup(SourceResolver.ROLE);
062:
063: String[] baseUris = getBaseURIs(publication);
064: for (int i = 0; i < baseUris.length; i++) {
065: String uri = baseUris[i] + "/" + path;
066:
067: if (getLogger().isDebugEnabled()) {
068: getLogger().debug(
069: "Trying to resolve URI [" + uri + "]");
070: }
071:
072: visitor.visit(resolver, uri);
073: }
074:
075: } catch (Exception e) {
076: throw new TemplatingException("Visiting path [" + path
077: + "] failed: ", e);
078: } finally {
079: if (resolver != null) {
080: this .manager.release(resolver);
081: }
082: }
083:
084: }
085:
086: private ServiceManager manager;
087:
088: /**
089: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
090: */
091: public void service(ServiceManager _manager)
092: throws ServiceException {
093: this .manager = _manager;
094: }
095:
096: /**
097: * Returns the publication.
098: * @return A publication. protected Publication getPublication1() { return
099: * this.publication; }
100: */
101:
102: /**
103: * Returns the base URIs in traversing order.
104: * @param publication The original publication.
105: * @return An array of strings.
106: */
107: protected String[] getBaseURIs(Publication publication) {
108:
109: List uris = new ArrayList();
110:
111: Publication[] publications = getPublications(publication);
112: for (int i = 0; i < publications.length; i++) {
113: uris.add(getBaseURI(publications[i]));
114: }
115:
116: String coreBaseURI = publication.getServletContext()
117: .getAbsolutePath()
118: + "/";
119: uris.add(coreBaseURI);
120:
121: return (String[]) uris.toArray(new String[uris.size()]);
122: }
123:
124: /**
125: * Returns the base URI for a certain publication.
126: * @param publication The publication.
127: * @return A string.
128: */
129: public static String getBaseURI(Publication publication) {
130: return publication.getDirectory().getAbsolutePath() + "/";
131: }
132:
133: /**
134: * @see org.apache.lenya.cms.publication.templating.PublicationTemplateManager#visit(org.apache.lenya.cms.publication.Publication,
135: * org.apache.lenya.cms.publication.templating.PublicationVisitor)
136: */
137: public void visit(Publication publication,
138: PublicationVisitor visitor) {
139: SourceResolver resolver = null;
140: try {
141: resolver = (SourceResolver) this .manager
142: .lookup(SourceResolver.ROLE);
143:
144: Publication[] publications = getPublications(publication);
145: for (int i = 0; i < publications.length; i++) {
146: if (getLogger().isDebugEnabled()) {
147: getLogger().debug(
148: "Visiting publication [" + publications[i]
149: + "]");
150: }
151: visitor.visit(publications[i]);
152: }
153:
154: } catch (Exception e) {
155: throw new TemplatingException(
156: "Visiting publications failed: ", e);
157: } finally {
158: if (resolver != null) {
159: this .manager.release(resolver);
160: }
161: }
162:
163: }
164:
165: /**
166: * Returns the publications in traversing order.
167: * @param publication The original publication.
168: * @return An array of strings.
169: */
170: protected Publication[] getPublications(Publication publication) {
171:
172: List publications = new ArrayList();
173:
174: publications.add(publication);
175:
176: String[] templateIds = publication.getTemplateIds();
177: for (int i = 0; i < templateIds.length; i++) {
178: try {
179: Publication template = publication.getFactory()
180: .getPublication(templateIds[i]);
181: Publication[] templateTemplates = getPublications(template);
182: publications.addAll(Arrays.asList(templateTemplates));
183: } catch (PublicationException e) {
184: throw new RuntimeException(e);
185: }
186: }
187:
188: return (Publication[]) publications
189: .toArray(new Publication[publications.size()]);
190: }
191:
192: /**
193: * @see org.apache.lenya.cms.publication.templating.PublicationTemplateManager#getSelectableHint(org.apache.lenya.cms.publication.Publication,
194: * org.apache.avalon.framework.service.ServiceSelector,
195: * java.lang.String)
196: */
197: public Object getSelectableHint(Publication publication,
198: ServiceSelector selector, final String originalHint)
199: throws ServiceException {
200: Object selectableHint = null;
201:
202: try {
203: ExistingServiceVisitor resolver = new ExistingServiceVisitor(
204: selector, originalHint, getLogger());
205: visit(publication, resolver);
206: selectableHint = resolver.getSelectableHint();
207: if (selectableHint == null) {
208: selectableHint = originalHint;
209: }
210:
211: } catch (Exception e) {
212: String message = "Resolving hint [" + originalHint
213: + "] failed: ";
214: getLogger().error(message, e);
215: throw new RuntimeException(message, e);
216: }
217: return selectableHint;
218: }
219:
220: /**
221: * Searches for a declared service of the form "publicationId/service".
222: */
223: public class ExistingServiceVisitor implements PublicationVisitor {
224:
225: /**
226: * Ctor.
227: * @param selector The service selector to use.
228: * @param hint The hint to check.
229: * @param logger The logger.
230: */
231: public ExistingServiceVisitor(ServiceSelector selector,
232: Object hint, Logger logger) {
233: this .selector = selector;
234: this .hint = hint;
235: this .logger = logger;
236: }
237:
238: private ServiceSelector selector;
239: private Object hint;
240: private Object selectableHint = null;
241: private Logger logger;
242:
243: /**
244: * @see org.apache.lenya.cms.publication.templating.PublicationVisitor#visit(org.apache.lenya.cms.publication.Publication)
245: */
246: public void visit(Publication publication) {
247: String publicationHint = publication.getId() + "/"
248: + this .hint;
249: boolean success = false;
250: if (this .selector.isSelectable(publicationHint)) {
251: this .selectableHint = publicationHint;
252: success = true;
253: }
254: if (this .logger.isDebugEnabled()) {
255: this .logger.debug("Checking hint [" + publicationHint
256: + "]: " + success);
257: }
258: }
259:
260: /**
261: * @return The publication hint that could be selected or
262: * <code>null</code> if no hint could be selected.
263: */
264: public Object getSelectableHint() {
265: return this.selectableHint;
266: }
267:
268: }
269:
270: }
|