You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lenya.apache.org by jw...@apache.org on 2005/04/25 11:20:22 UTC
svn commit: r164549 -
/lenya/trunk/src/java/org/apache/lenya/cms/publication/DocumentTypeBuilderImpl.java
Author: jwkaltz
Date: Mon Apr 25 02:20:21 2005
New Revision: 164549
URL: http://svn.apache.org/viewcvs?rev=164549&view=rev
Log:
implementation of DocumentTypeBuilder as an Avalon Service
Added:
lenya/trunk/src/java/org/apache/lenya/cms/publication/DocumentTypeBuilderImpl.java (with props)
Added: lenya/trunk/src/java/org/apache/lenya/cms/publication/DocumentTypeBuilderImpl.java
URL: http://svn.apache.org/viewcvs/lenya/trunk/src/java/org/apache/lenya/cms/publication/DocumentTypeBuilderImpl.java?rev=164549&view=auto
==============================================================================
--- lenya/trunk/src/java/org/apache/lenya/cms/publication/DocumentTypeBuilderImpl.java (added)
+++ lenya/trunk/src/java/org/apache/lenya/cms/publication/DocumentTypeBuilderImpl.java Mon Apr 25 02:20:21 2005
@@ -0,0 +1,339 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.lenya.cms.publication;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.avalon.excalibur.pool.Poolable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.lenya.cms.authoring.DefaultBranchCreator;
+import org.apache.lenya.cms.authoring.ParentChildCreatorInterface;
+import org.xml.sax.SAXException;
+
+
+/**
+ * A service for building an instance of DocumentType.
+ *
+ * Since this service is very frequently used, it is implemented as a poolable
+ * service. Furthermore, the instances are cached, to avoid re-reading
+ * configuration unless necessary (that is, when the configuration file
+ * has changed).
+ *
+ * @version $Id$
+ */
+public final class DocumentTypeBuilderImpl extends AbstractLogEnabled implements DocumentTypeBuilder, Serviceable, Poolable {
+
+ /** Creates a new instance of DocumentTypeBuilder */
+ public DocumentTypeBuilderImpl() {
+ // do nothing
+ }
+
+ /**
+ * The default document types configuration directory, relative to the publication directory.
+ */
+ private static final String DOCTYPE_DIRECTORY = "config/doctypes".replace('/', File.separatorChar);
+
+ /**
+ * The location of sample contents for this resource type.
+ * Note that this need not be a file.
+ */
+ private static final String DOCTYPE_SAMPLES = "config/doctypes/samples/";
+
+ /**
+ * <code>CONFIG_FILE</code> The default document types configuration file, relative to the publication directory.
+ */
+ public static final String CONFIG_FILE = "doctypes.xconf";
+ /**
+ * <code>DOCTYPES_ELEMENT</code> The doctypes element
+ */
+ public static final String DOCTYPES_ELEMENT = "doctypes";
+ /**
+ * <code>DOCTYPE_ELEMENT</code> The doctype element
+ */
+ public static final String DOCTYPE_ELEMENT = "doc";
+ /**
+ * <code>TYPE_ATTRIBUTE</code> The type attribute
+ */
+ public static final String TYPE_ATTRIBUTE = "type";
+ /**
+ * <code>CREATOR_ELEMENT</code> The creator element
+ */
+ public static final String CREATOR_ELEMENT = "creator";
+ /**
+ * <code>SRC_ATTRIBUTE</code> The src attribute
+ */
+ public static final String SRC_ATTRIBUTE = "src";
+ /**
+ * <code>WORKFLOW_ELEMENT</code> The workflow element
+ */
+ public static final String WORKFLOW_ELEMENT = "workflow";
+ /**
+ * <code>ELEMENT_REWRITE_ATTRIBUTE</code> The link-attribute element.
+ */
+ public static final String ELEMENT_REWRITE_ATTRIBUTE = "link-attribute";
+ /**
+ * <code>ATTRIBUTE_XPATH</code> The xpath attribute.
+ */
+ public static final String ATTRIBUTE_XPATH = "xpath";
+
+ /**
+ * <code>SAMPLE_NAME</code> The sample name parameter
+ */
+ public static final String SAMPLE_NAME = "sample-name";
+
+
+
+ /**
+ * Builds an instance of document type for a given resource type name.
+ *
+ * @param name The name of the resource type
+ * @param publication The publication the document type belongs to.
+ * @return A document type object.
+ * @throws DocumentTypeBuildException When something went wrong.
+ */
+ public DocumentType buildDocumentType(String name, Publication publication)
+ throws DocumentTypeBuildException {
+
+ if (publication == null)
+ throw new DocumentTypeBuildException("illegal usage, publication is null");
+
+ // see if configuration has changed since last load.
+ // if it has, do not use cache.
+ boolean useCache = isEntryUptodate(confLastModifiedCache,
+ publication.getId(),
+ getDocTypeConfigFile(publication).lastModified());
+
+ // this will refer to the returned instance
+ DocumentType type = null;
+
+ if (useCache) {
+ // try to get an instance from cache
+ type = docTypeCache.get(publication.getId(), name);
+ }
+
+ if (getLogger().isDebugEnabled())
+ getLogger().debug("buildDocumentType() called with name [" + name + "], publication.getId [" + publication.getId() + "], lookInCache [" + useCache + "], is in cache [" + (type != null) + "]");
+
+ if (type == null) {
+
+ // create a new instance of DocumentType
+ type = new DocumentType(name, getLogger());
+
+ try {
+ // retrieve configuration for this publication
+ Configuration configuration = getDocTypeConfiguration(publication);
+
+ // now get configuration for this resource type
+ Configuration[] doctypeConfigurations = configuration.getChildren(DOCTYPE_ELEMENT);
+
+ Configuration doctypeConf = null;
+
+ for (int i = 0; i < doctypeConfigurations.length; i++) {
+ if (doctypeConfigurations[i].getAttribute(TYPE_ATTRIBUTE).equals(name)) {
+ doctypeConf = doctypeConfigurations[i];
+ break;
+ }
+ }
+
+ if (doctypeConf == null) {
+ throw new DocumentTypeBuildException("No definition found for doctype '" + name);
+ }
+
+ ParentChildCreatorInterface creator;
+ Configuration creatorConf = doctypeConf.getChild(CREATOR_ELEMENT, false);
+
+ if (creatorConf != null) {
+ String creatorClassName = creatorConf.getAttribute(SRC_ATTRIBUTE);
+ Class creatorClass = Class.forName(creatorClassName);
+ creator = (ParentChildCreatorInterface) creatorClass.newInstance();
+ creator.init(creatorConf);
+ } else {
+ creator = new DefaultBranchCreator();
+ }
+
+ type.setCreator(creator);
+
+ // determine the sample content location.
+ if (creatorConf != null) {
+ Configuration sampleConf = creatorConf.getChild(SAMPLE_NAME, false);
+ if (sampleConf != null) {
+ String sampleLocation = sampleConf.getValue();
+ type.setSampleContentLocation(publication.getDirectory() + "/" + DOCTYPE_SAMPLES + sampleLocation);
+ }
+ }
+
+
+ Configuration workflowConf = doctypeConf.getChild(WORKFLOW_ELEMENT, false);
+
+ if (workflowConf != null) {
+ String workflowFileName = workflowConf.getAttribute(SRC_ATTRIBUTE);
+ type.setWorkflowFileName(workflowFileName);
+ }
+
+ Configuration[] rewriteAttributeConfigs = doctypeConf.getChildren(ELEMENT_REWRITE_ATTRIBUTE);
+ List xPaths = new ArrayList();
+ for (int i = 0; i < rewriteAttributeConfigs.length; i++) {
+ String xPath = rewriteAttributeConfigs[i].getAttribute(ATTRIBUTE_XPATH);
+ xPaths.add(xPath);
+ }
+ String[] xPathArray = (String[]) xPaths.toArray(new String[xPaths.size()]);
+ type.setLinkAttributeXPaths(xPathArray);
+
+ docTypeCache.add(publication.getId(), name, type);
+
+ } catch (final ConfigurationException e) {
+ throw new DocumentTypeBuildException(e);
+ } catch (final SAXException e) {
+ throw new DocumentTypeBuildException(e);
+ } catch (final IOException e) {
+ throw new DocumentTypeBuildException(e);
+ } catch (final DocumentTypeBuildException e) {
+ throw new DocumentTypeBuildException(e);
+ } catch (final ClassNotFoundException e) {
+ throw new DocumentTypeBuildException(e);
+ } catch (final InstantiationException e) {
+ throw new DocumentTypeBuildException(e);
+ } catch (final IllegalAccessException e) {
+ throw new DocumentTypeBuildException(e);
+ }
+ }
+
+ return type;
+ }
+
+ // for each publication key, stores a hash of docType objects
+ private DocTypeCache docTypeCache = new DocTypeCache();
+
+
+ private Hashtable confCache = new Hashtable();
+ private Hashtable confLastModifiedCache = new Hashtable();
+
+ private Configuration getDocTypeConfiguration(Publication _publication) throws DocumentTypeBuildException, SAXException, IOException, ConfigurationException {
+
+ Object conf = confCache.get(_publication.getId());
+
+ if (getLogger().isDebugEnabled())
+ getLogger().debug("getDocTypeConfiguration() for publication [" + _publication.getId() + "], conf in cache ? " + (conf != null));
+
+ File configFile = getDocTypeConfigFile(_publication);
+ if (! configFile.exists())
+ throw new DocumentTypeBuildException("configuration file for publication [" + _publication.getId() + "] does not exist");
+
+ if (conf == null ||
+ ! isEntryUptodate(confLastModifiedCache,
+ _publication.getId(),
+ configFile.lastModified())) {
+
+ // load / reload the configuration from file
+ if (getLogger().isDebugEnabled())
+ getLogger().debug("getDocTypeConfiguration() reloading configuration for publication [" + _publication.getId() + "]");
+
+ conf = new DefaultConfigurationBuilder().buildFromFile(configFile);
+
+ // put in cache
+ confCache.put(_publication.getId(), conf);
+ confLastModifiedCache.put(_publication.getId(),
+ new Long(configFile.lastModified()));
+ }
+
+ return (Configuration) conf;
+ }
+
+ private boolean isEntryUptodate(Hashtable entryTimestamps, String key, long timestamp) {
+
+ boolean isUptodate = false;
+ Object lastModifiedEntry = entryTimestamps.get(key);
+ if (lastModifiedEntry != null) {
+ long oldTimestamp = ((Long)lastModifiedEntry).longValue();
+ if (timestamp <= oldTimestamp)
+ isUptodate = true;
+
+ if (getLogger().isDebugEnabled())
+ getLogger().debug("isEntryUptodate() called for key [" + key + "] and timestamp [" + timestamp + "], current timestamp is [" + timestamp + "], returning " + isUptodate);
+
+ }
+ else {
+ if (getLogger().isDebugEnabled())
+ getLogger().debug("isEntryUptodate() has no previous entry, returning [" + isUptodate);
+ }
+
+ return isUptodate;
+ }
+
+ /** configFile must exist; otherwise exception is thrown */
+ private File getDocTypeConfigFile(Publication _publication) throws DocumentTypeBuildException {
+
+ File configDirectory = new File(_publication.getDirectory(), DOCTYPE_DIRECTORY);
+ File ret = new File(configDirectory, CONFIG_FILE);
+ if (! ret.exists())
+ throw new DocumentTypeBuildException("Resource types configuration file for publication " + _publication.getId() + " does not exist; should be located at [" + ret.getPath() + "]");
+
+ return ret;
+ }
+
+ protected ServiceManager manager;
+
+ /**
+ * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+ */
+ public void service(ServiceManager manager) throws ServiceException {
+ this.manager = manager;
+ }
+
+
+ private class DocTypeCache {
+
+ // for each publication key, stores a hash of docType objects
+ private Hashtable cache = new Hashtable();
+
+ void add(String publicationId, String docTypeName, DocumentType type) {
+ Object docTypes = cache.get(publicationId);
+ if (docTypes == null) {
+ Hashtable docTypesTable = new Hashtable();
+ docTypesTable.put(docTypeName, type);
+ cache.put(publicationId, docTypesTable);
+ }
+ else {
+ Hashtable docTypesTable = (Hashtable)docTypes;
+ docTypesTable.put(docTypeName, type);
+ }
+ }
+
+ DocumentType get(String publicationId, String docTypeName) {
+ DocumentType ret = null;
+ Object docTypes = cache.get(publicationId);
+ if (docTypes != null) {
+ Hashtable docTypesTable = (Hashtable)docTypes;
+ ret = (DocumentType)docTypesTable.get(docTypeName);
+ }
+ return ret;
+ }
+ }
+
+
+}
Propchange: lenya/trunk/src/java/org/apache/lenya/cms/publication/DocumentTypeBuilderImpl.java
------------------------------------------------------------------------------
svn:keywords = Id
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@lenya.apache.org
For additional commands, e-mail: commits-help@lenya.apache.org