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: package org.apache.lenya.cms.publication;
019:
020: import java.util.Arrays;
021: import java.util.StringTokenizer;
022:
023: import org.apache.avalon.framework.container.ContainerUtil;
024: import org.apache.avalon.framework.logger.AbstractLogEnabled;
025: import org.apache.avalon.framework.logger.Logger;
026: import org.apache.avalon.framework.service.ServiceException;
027: import org.apache.avalon.framework.service.ServiceManager;
028: import org.apache.lenya.cms.repository.RepositoryException;
029: import org.apache.lenya.cms.repository.RepositoryItem;
030: import org.apache.lenya.cms.repository.Session;
031: import org.apache.lenya.cms.site.SiteStructure;
032: import org.apache.lenya.util.Assert;
033:
034: /**
035: * A DocumentIdentityMap avoids the multiple instanciation of a document object.
036: *
037: * @version $Id: DocumentIdentityMap.java 264153 2005-08-29 15:11:14Z andreas $
038: */
039: public class DocumentFactoryImpl extends AbstractLogEnabled implements
040: DocumentFactory {
041:
042: private Session session;
043: protected ServiceManager manager;
044:
045: /**
046: * @return The session.
047: */
048: public Session getSession() {
049: return this .session;
050: }
051:
052: /**
053: * Ctor.
054: * @param session The session to use.
055: * @param manager The service manager.
056: * @param logger The logger to use.
057: */
058: public DocumentFactoryImpl(Session session, ServiceManager manager,
059: Logger logger) {
060: this .session = session;
061: this .manager = manager;
062: ContainerUtil.enableLogging(this , logger);
063: }
064:
065: /**
066: * Returns a document.
067: * @param publication The publication.
068: * @param area The area.
069: * @param uuid The document UUID.
070: * @param language The language.
071: * @return A document.
072: * @throws DocumentBuildException if an error occurs.
073: */
074: public Document get(Publication publication, String area,
075: String uuid, String language) throws DocumentBuildException {
076: return get(publication, area, uuid, language, -1);
077: }
078:
079: public Document get(Publication publication, String area,
080: String uuid, String language, int revision)
081: throws DocumentBuildException {
082: if (getLogger().isDebugEnabled())
083: getLogger().debug(
084: "DocumentIdentityMap::get() called on publication ["
085: + publication.getId() + "], area [" + area
086: + "], UUID [" + uuid + "], language ["
087: + language + "]");
088:
089: String key = getKey(publication, area, uuid, language, revision);
090:
091: if (getLogger().isDebugEnabled())
092: getLogger().debug(
093: "DocumentIdentityMap::get() got key [" + key
094: + "] from DocumentFactory");
095:
096: try {
097: return (Document) getSession().getRepositoryItem(this , key);
098: } catch (RepositoryException e) {
099: throw new DocumentBuildException(e);
100: }
101: }
102:
103: /**
104: * Returns the document identified by a certain web application URL.
105: * @param webappUrl The web application URL.
106: * @return A document.
107: * @throws DocumentBuildException if an error occurs.
108: */
109: public Document getFromURL(String webappUrl)
110: throws DocumentBuildException {
111: String key = getKey(webappUrl);
112: try {
113: return (Document) getSession().getRepositoryItem(this , key);
114: } catch (RepositoryException e) {
115: throw new DocumentBuildException(e);
116: }
117: }
118:
119: /**
120: * Builds a clone of a document for another language.
121: * @param document The document to clone.
122: * @param language The language of the target document.
123: * @return A document.
124: * @throws DocumentBuildException if an error occurs.
125: */
126: public Document getLanguageVersion(Document document,
127: String language) throws DocumentBuildException {
128: return get(document.getPublication(), document.getArea(),
129: document.getUUID(), language);
130: }
131:
132: /**
133: * Builds a clone of a document for another area.
134: * @param document The document to clone.
135: * @param area The area of the target document.
136: * @return A document.
137: * @throws DocumentBuildException if an error occurs.
138: */
139: public Document getAreaVersion(Document document, String area)
140: throws DocumentBuildException {
141: return get(document.getPublication(), area, document.getUUID(),
142: document.getLanguage());
143: }
144:
145: /**
146: * Builds a document for the default language.
147: * @param publication The publication.
148: * @param area The area.
149: * @param documentId The document ID.
150: * @return A document.
151: * @throws DocumentBuildException if an error occurs.
152: */
153: public Document get(Publication publication, String area,
154: String documentId) throws DocumentBuildException {
155: return get(publication, area, documentId, publication
156: .getDefaultLanguage());
157: }
158:
159: /**
160: * Checks if a string represents a valid document ID.
161: * @param id The string.
162: * @return A boolean value.
163: */
164: public boolean isValidDocumentId(String id) {
165:
166: if (!id.startsWith("/")) {
167: return false;
168: }
169:
170: String[] snippets = id.split("/");
171:
172: if (snippets.length < 2) {
173: return false;
174: }
175:
176: for (int i = 1; i < snippets.length; i++) {
177: if (!snippets[i].matches("[a-zA-Z0-9\\-]+")) {
178: return false;
179: }
180: }
181:
182: return true;
183: }
184:
185: /**
186: * Checks if a webapp URL represents a document.
187: * @param webappUrl A web application URL.
188: * @return A boolean value.
189: * @throws DocumentBuildException if an error occurs.
190: */
191: public boolean isDocument(String webappUrl)
192: throws DocumentBuildException {
193: Assert.notNull("webapp URL", webappUrl);
194: PublicationManager pubMgr = getPubManager();
195: try {
196: URLInformation info = new URLInformation(webappUrl);
197: String pubId = info.getPublicationId();
198: if (pubId != null
199: && Arrays.asList(pubMgr.getPublicationIds())
200: .contains(pubId)) {
201: Publication pub = pubMgr.getPublication(this , pubId);
202: DocumentBuilder builder = pub.getDocumentBuilder();
203: return builder.isDocument(this , webappUrl);
204: } else {
205: return false;
206: }
207: } catch (PublicationException e) {
208: throw new DocumentBuildException(e);
209: }
210: }
211:
212: /**
213: * Builds a document key.
214: * @param publication The publication.
215: * @param area The area.
216: * @param uuid The document UUID.
217: * @param language The language.
218: * @param revision
219: * @return A key.
220: */
221: public String getKey(Publication publication, String area,
222: String uuid, String language, int revision) {
223: Assert.notNull("publication", publication);
224: Assert.notNull("area", area);
225: Assert.notNull("uuid", uuid);
226: Assert.notNull("language", language);
227: return publication.getId() + ":" + area + ":" + uuid + ":"
228: + language + ":" + revision;
229: }
230:
231: /**
232: * Builds a document key.
233: * @param webappUrl The web application URL.
234: * @return A key.
235: */
236: public String getKey(String webappUrl) {
237: Assert.notNull("webapp URL", webappUrl);
238: try {
239: if (!isDocument(webappUrl)) {
240: throw new RuntimeException("No document for URL ["
241: + webappUrl + "] found.");
242: }
243: DocumentLocator locator = getLocator(webappUrl);
244: Publication publication = getPublication(locator
245: .getPublicationId());
246: String area = locator.getArea();
247: String uuid = publication.getArea(area).getSite().getNode(
248: locator.getPath()).getUuid();
249: return getKey(publication, area, uuid, locator
250: .getLanguage(), -1);
251: } catch (Exception e) {
252: throw new RuntimeException(e);
253: }
254: }
255:
256: protected DocumentLocator getLocator(String webappUrl) {
257: DocumentLocator locator;
258: try {
259: Publication publication = PublicationUtil
260: .getPublicationFromUrl(this .manager, this ,
261: webappUrl);
262: DocumentBuilder builder = publication.getDocumentBuilder();
263: locator = builder.getLocator(this , webappUrl);
264:
265: } catch (Exception e) {
266: throw new RuntimeException(e);
267: }
268: return locator;
269: }
270:
271: /**
272: * @see org.apache.lenya.transaction.IdentifiableFactory#build(org.apache.lenya.transaction.IdentityMap,
273: * java.lang.String)
274: */
275: public RepositoryItem buildItem(Session session, String key)
276: throws RepositoryException {
277: if (getLogger().isDebugEnabled())
278: getLogger().debug(
279: "DocumentFactory::build() called with key [" + key
280: + "]");
281:
282: StringTokenizer tokenizer = new StringTokenizer(key, ":");
283: String publicationId = tokenizer.nextToken();
284: String area = tokenizer.nextToken();
285: String uuid = tokenizer.nextToken();
286: String language = tokenizer.nextToken();
287: String revisionString = tokenizer.nextToken();
288: int revision = Integer.valueOf(revisionString).intValue();
289:
290: Document document;
291: try {
292: Publication publication = getPublication(publicationId);
293: DocumentBuilder builder = publication.getDocumentBuilder();
294: DocumentIdentifier identifier = new DocumentIdentifier(
295: publicationId, area, uuid, language);
296: document = buildDocument(this , identifier, revision,
297: builder);
298: } catch (Exception e) {
299: throw new RepositoryException(e);
300: }
301: if (getLogger().isDebugEnabled())
302: getLogger().debug("DocumentFactory::build() done.");
303:
304: return document;
305: }
306:
307: protected Document buildDocument(DocumentFactory map,
308: DocumentIdentifier identifier, int revision,
309: DocumentBuilder builder) throws DocumentBuildException {
310:
311: DocumentImpl document = createDocument(map, identifier,
312: revision, builder);
313: ContainerUtil.enableLogging(document, getLogger());
314: return document;
315: }
316:
317: /**
318: * Creates a new document object. Override this method to create specific document objects,
319: * e.g., for different document IDs.
320: * @param map The identity map.
321: * @param identifier The identifier.
322: * @param revision The revision or -1 for the latest revision.
323: * @param builder The document builder.
324: * @return A document.
325: * @throws DocumentBuildException when something went wrong.
326: */
327: protected DocumentImpl createDocument(DocumentFactory map,
328: DocumentIdentifier identifier, int revision,
329: DocumentBuilder builder) throws DocumentBuildException {
330: return new DocumentImpl(this .manager, map, identifier,
331: revision, getLogger());
332: }
333:
334: public Document get(DocumentIdentifier identifier)
335: throws DocumentBuildException {
336: try {
337: Publication pub = getPublication(identifier
338: .getPublicationId());
339: return get(pub, identifier.getArea(), identifier.getUUID(),
340: identifier.getLanguage());
341: } catch (PublicationException e) {
342: throw new DocumentBuildException(e);
343: }
344: }
345:
346: public String getItemType() {
347: return Document.TRANSACTIONABLE_TYPE;
348: }
349:
350: public Document get(DocumentLocator locator)
351: throws DocumentBuildException {
352: try {
353: Publication pub = getPublication(locator.getPublicationId());
354: SiteStructure site = pub.getArea(locator.getArea())
355: .getSite();
356: String uuid = site.getNode(locator.getPath()).getUuid();
357: return get(pub, locator.getArea(), uuid, locator
358: .getLanguage());
359: } catch (PublicationException e) {
360: throw new DocumentBuildException(e);
361: }
362: }
363:
364: public Publication getPublication(String id)
365: throws PublicationException {
366: return getPubManager().getPublication(this , id);
367: }
368:
369: public Publication[] getPublications() {
370: return getPubManager().getPublications(this );
371: }
372:
373: private PublicationManager pubManager;
374:
375: protected PublicationManager getPubManager() {
376: if (this .pubManager == null) {
377: try {
378: this .pubManager = (PublicationManager) this .manager
379: .lookup(PublicationManager.ROLE);
380: } catch (ServiceException e) {
381: throw new RuntimeException(e);
382: }
383: }
384: return this .pubManager;
385: }
386:
387: public boolean existsPublication(String id) {
388: return Arrays.asList(getPubManager().getPublicationIds())
389: .contains(id);
390: }
391:
392: }
|