/* * Copyright (C) 2009 Peter Boy All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.arsdigita.cms; import com.arsdigita.cms.contentsection.ContentSectionConfig; import com.arsdigita.cms.contentsection.ContentSectionSetup; import com.arsdigita.cms.contenttypes.XMLContentTypeHandler; import com.arsdigita.cms.portlet.ContentDirectoryPortlet; import com.arsdigita.cms.portlet.ContentItemPortlet; import com.arsdigita.cms.portlet.ContentSectionsPortlet; import com.arsdigita.cms.portlet.TaskPortlet; import com.arsdigita.cms.util.Util; import com.arsdigita.formbuilder.util.FormbuilderSetup; import com.arsdigita.kernel.Kernel; import com.arsdigita.kernel.KernelExcursion; import com.arsdigita.kernel.permissions.PrivilegeDescriptor; import com.arsdigita.loader.PackageLoader; import com.arsdigita.persistence.DataQuery; import com.arsdigita.persistence.SessionManager; import com.arsdigita.runtime.ScriptContext; import com.arsdigita.util.parameter.Parameter; import com.arsdigita.util.parameter.StringArrayParameter; import com.arsdigita.web.Application; import com.arsdigita.web.ApplicationType; import com.arsdigita.xml.XML; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.log4j.Logger; /** *

Executes nonrecurring at install time and loads (installs and initializes) * the Content Management System module,including the Content Center, CMS * Service applications, and CMS Mime Types service persistently into * database.

* *

This class also optionally initializes user-defined content types.

*

Additional user-defined content sections can be loaded and initilized * using the recurring

initializer
at any startup. * *

The tasks to perform are:

  1. create CMS package * type(content-section)
  2. create ContentCenter package type and * instance
  3. create CMS Service package type and instance
  4. *
  5. create CMS package (content-section) instance
* *

Configuration can be modified by configuration parameters before * processing, otherwise hardcoded default values take effect. After processing, * the installation values can not be modified anymore without a fresh * installation of the whole system.

* * NOTE: Configuration parameters used at load time MUST be part of Loader * class and can not delegated to a Config object (derived from AbstractConfig). * They will (and can) not be persisted into an registry object (file). * * @author Peter Boy <pboy@barkhof.uni-bremen.de> * @since ccm-cms version 6.6.0 * @version $Id: Loader.java 2305 2012-05-01 12:26:33Z pboy $ */ public class Loader extends PackageLoader { /** * Creates a s_logging category with name = full name of class */ private static final Logger s_log = Logger.getLogger(Loader.class); /** * Loader configuration object, singleton design pattern NOTE: LoaderConfig * only supplies unmutable hard coded defaults! It is not possible to alter * any of the contained values by specifiying an configuration parameter * during load step. If a configuration value has to be configurable at load * time, the parameter must be relocated into this Loader class! */ private static final LoaderConfig s_conf = LoaderConfig.getInstance(); // /////////////////////////////////////////////////////////////////// // Configurable parameters during load step. // /////////////////////////////////////////////////////////////////// /** * The name(s) of the content section(s). In case of more than one name the * first is treated as default section. Otherwise the section created is the * default section. More sections can always be created during a subsequent * system startup using initialization parameters or using the * content section GUI. * * If you change the default value below you have to adjust the appropriate * bundle loader's default domain mapping as well! */ /* NON Javadoc comment: * Criteria for the name of the standard content section: * - the wording should be meaningful in several languages (no specific * english term) * - should be non-trivial (like "content") * Candidates: * - info * - public / publ */ private final Parameter m_contentSectionNames = new StringArrayParameter( "com.arsdigita.cms.loader.section_names", Parameter.REQUIRED, new String[]{"info"}); // /////////////////////////////////////////////////////////////////// // Configurable parameters during load step END. // /////////////////////////////////////////////////////////////////// /** * List of classnames of internal base content types (needed in every * section created), generated while loading those content types in * loadContentTypeDefinitions(files) for later use in register step. */ private ArrayList m_content_type_list = new ArrayList(); /** * Standard constructor. */ public Loader() { s_log.debug("CMS.loader (Constructor) invoked"); register(m_contentSectionNames); s_log.debug("CMS.loader (Constructor) completed"); } /** * */ public void run(final ScriptContext ctx) { s_log.debug("CMS.loader.run() invoked"); new KernelExcursion() { public void excurse() { setEffectiveParty(Kernel.getSystemParty()); // Step 1) Setup the CMS ContentCenter ApplicationType appType = loadContentCenterApplicationType(); setupDefaultContentCenterApplicationInstance(appType); // Step 2) Setup the CMS global services appType = loadServiceApplicationType(); setupDefaultServiceApplicationInstance(appType); // Step 3) load (cms internal) content type definition(s) loadContentTypeDefinitions(s_conf.getCTDefFiles()); // Step 4) Load CMS content section // Loads content section application type and instance in one step loadContentSection((String[]) get(m_contentSectionNames)); // Step 5) Loading CMS portlets s_log.debug("CMS.loader going to load portlets"); ContentDirectoryPortlet.loadPortletType(); ContentItemPortlet.loadPortletType(); ContentSectionsPortlet.loadPortletType(); TaskPortlet.loadPortletType(); // Loading forms widget into database FormbuilderSetup fbs = new FormbuilderSetup(); fbs.setup(s_conf.getWidgetTypes(), s_conf.getProcessListenerTypes(), s_conf.getDataQueries()); } }.run(); } /** * Loads the ContentCenter subpackage (content-center) into the database. * * It is made public to be able to invoke it from the update script (e.g. * 6.6.1-6.6.2). We need separate steps for loading and instantiating * because update skript requires. */ public static ApplicationType loadContentCenterApplicationType() { s_log.debug("Creating CMS ContentCenter..."); /* * Create new type legacy free application type NOTE: The wording in the * title parameter of ApplicationType determines the name of the * subdirectory for the XSL stylesheets. It gets "urlized", i.e. * trimming leading and trailing blanks and replacing blanks between * words and illegal characters with an hyphen and converted to lower * case. "Content Center" will become "content-center". */ ApplicationType type = new ApplicationType(ContentCenter.INSTANCE_NAME, ContentCenter.BASE_DATA_OBJECT_TYPE); type.setDescription("The content center workspace for content creators."); type.setSingleton(true); type.save(); s_log.debug("CMS ContentCenter type created."); return type; } /** * Instantiates the ContentCenter subpackage (content-center) (in the database). * * It is made public to be able to invoke it from the update script (e.g. * 6.6.1-6.6.2). We need separate steps for loading and instantiating * because update skript requires. * * @param workspaceType */ public static void setupDefaultContentCenterApplicationInstance( ApplicationType appType) { // create application instance // Whether a legacy compatible or a legacy free application is // created depends on the type of ApplicationType above. No need to // modify anything here in the migration process // old-style package key used as url fragment where to install the instance s_log.debug("Creating CMS ContentCenter instance ..."); ContentCenter app = (ContentCenter) Application.createApplication( ContentCenter.BASE_DATA_OBJECT_TYPE, // type ContentCenter.PACKAGE_KEY, // url fragment ContentCenter.INSTANCE_NAME, // title null); // parent app.setDescription("The default CMS ContentCenter instance."); app.save(); s_log.debug("CMS ContentCenter instance " + ContentCenter.PACKAGE_KEY + " created."); s_log.debug("Done loading CMS ContentCenter."); } /** * CMS Service application is used by the Content Management System as a * store for global resources and assets. It is made public to be able to * invoke it from the update script (e.g. 6.6.1-6.6.2). */ public static ApplicationType loadServiceApplicationType() { s_log.debug("Loading CMS Servce Package..."); /* * Create new type legacy free application type NOTE: The wording in the * title parameter of ApplicationType determines the name of the * subdirectory for the XSL stylesheets. It gets "urlized", i.e. * trimming leading and trailing blanks and replacing blanks between * words and illegal characters with an hyphen and converted to lower * case. "CMS Service" will become "cms-service". */ ApplicationType type = new ApplicationType("CMS Service", Service.BASE_DATA_OBJECT_TYPE); type.setDescription("Services to store global resources and assets."); type.setSingleton(true); type.save(); return type; } /** * * @param serviceType */ public static void setupDefaultServiceApplicationInstance( ApplicationType serviceType) { // create legacy compatible application instance, // old-style package key used as url fragment where to install the instance Service app = (Service) Application.createApplication( serviceType, // type Service.PRIMARY_URL_STUB, // url fragment "CMS Service Instance", // title null); // parent app.setDescription("The default CMS service instance."); app.save(); s_log.debug("Done creating CMS Service Package."); } /** * Load a content section application type and an initial default * content-section instance(s). Some configuration values which are to be * considered as unmutable are specified in LoaderConfig. Uses new style * application in legacy compatible mode. * * NOTE: At ccm-cms load time no content type packages are available because * any content type depends on ccm-cms. Therefore, the loading step can not * process content type package assignment! Instead each content type itself * must assign itself to an appropriate content section at it's load time. * Cf. {@link com.arsdigita.cms.contenttype.AbstractContentTypeLoader}. * * But the load step has to process the cms internal content types! */ private void loadContentSection(String[] sectionNames) { // Step 1: Create content section application type // prerequisite for concrete content-section instance creation. /* * Create legacy-free application type NOTE: The wording in the title * parameter of ApplicationType determines the name of the subdirectory * for the XSL stylesheets. It gets "urlized", i.e. trimming leading and * trailing blanks and replacing blanks between words and illegal * characters with an hyphen and converted to lower case. "Content * Section" will become "content-section". */ ApplicationType type = new ApplicationType( "Content Section", ContentSection.BASE_DATA_OBJECT_TYPE); type.setDescription("The CMS Content Section application."); type.save(); // Step 2: Load CMS specific privileges into central (core) privilege // system. createPrivileges(); // Step 3: Create the installation default content section(s). // ContentSection.create creates a section with several default values // which have to be adopted for a concrete installation. for (int i = 0; i < sectionNames.length; i++) { final String sectionName = sectionNames[i]; s_log.debug("Creating content section on /" + sectionName); // Step 1: Validate name for section Util.validateURLParameter("name", sectionName); ContentSectionConfig conf = new ContentSectionConfig(); conf.load(); ContentSectionSetup.setupContentSectionAppInstance( sectionName, conf.getDefaultRoles(), conf.getDefaultWorkflows(), s_conf.isPubliclyViewable(), s_conf.getItemResolverClass(), s_conf.getTemplateResolverClass(), m_content_type_list, s_conf.getUseSectionCategories(), s_conf.getCategoryFileList() ); } } /** * Parses XML file definition of (internal) base content types and loads * them into database. It fulfills a task similiar to the Loader of external * content type packages. * * The XML config looks like the example below, the "parentType" and "name" * attributes are optional, and only required for creating User Defined * ContentTypes. Label corresponds to ContentType's label and can be * multiple words, and "name" to DynamicObject's name property, and must be * a single word. The objectType attribute is ignored for UDCTs, as it gets * dynamically generated. * * UDCT Copyright *
     * <ccm:content-types>
     *   <ccm:content-type
     *             name="Copyright"
     *             label="UDCT Copyright"
     *             parentType="com.arsdigita.cms.contenttypes.Address"
     *             classname="com.arsdigita.cms.contenttypes.Address"
     *             description="Copyright for storing copyright information"
     *             objectType="com.arsdigita.cms.contentTypes.Address" >
     *
     *      <ccm:authoring-kit>
     *      </ccm:authoring-kit>
     *   </ccm:content-type>
     * </ccm:content-types>
     * 
* * @see XMLContentTypeHandler */ private void loadContentTypeDefinitions(List ctDefFiles) { s_log.debug("Loading content type definitions ..."); if (ctDefFiles != null) { XMLContentTypeHandler handler = new XMLContentTypeHandler(); Iterator i = ctDefFiles.iterator(); while (i.hasNext()) { String xmlFile = (String) i.next(); s_log.debug("Processing contentTypes in: " + xmlFile); XML.parseResource(xmlFile, handler); } Iterator iter = handler.getContentTypes().iterator(); while (iter.hasNext()) { ContentType ct = (ContentType) iter.next(); if (!ct.isInternal()) { m_content_type_list.add(ct.getClassName()); } } } s_log.debug("Done loading content type definitions."); } /** * Integrates the CMS privileges into the Core permision system. * * Skips through the CMS specific privileges and integrates those which are * missing in core's acs_privileges into it, so the systems security system * is aware of it. */ private static void createPrivileges() { s_log.debug("Creating Privileges..."); final String CMS_PRIVILEGES = "com.arsdigita.cms.getPrivileges"; final String PRIVILEGE = "privilege"; DataQuery dq = SessionManager.getSession().retrieveQuery(CMS_PRIVILEGES); try { while (dq.next()) { String privilege = (String) dq.get(PRIVILEGE); s_log.debug(String.format("privilege = %s", privilege)); if (PrivilegeDescriptor.get(privilege) == null) { PrivilegeDescriptor.createPrivilege(privilege); } } } finally { dq.close(); } s_log.debug("Done creating Privileges."); } }