413 lines
17 KiB
Java
Executable File
413 lines
17 KiB
Java
Executable File
/*
|
|
* Copyright (C) 2009 Peter Boy <pb@zes.uni-bremen.de> 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;
|
|
|
|
/**
|
|
* <p>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.</p>
|
|
*
|
|
* <p>This class also optionally initializes user-defined content types. </p>
|
|
* <p>Additional user-defined content sections can be loaded and initilized
|
|
* using the recurring
|
|
* <pre>initializer</pre> at any startup.
|
|
*
|
|
* <p>The tasks to perform are:</p> <ol> <li>create CMS package
|
|
* type(content-section)</li> <li>create Workspace package type and
|
|
* instance</li> <li>create CMS Service package type and instance</li>
|
|
* <li>create CMS package (content-section) instance</li> </ol>
|
|
*
|
|
* <p>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.</p>
|
|
*
|
|
* @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.
|
|
*/
|
|
private final Parameter m_contentSectionNames = new StringArrayParameter(
|
|
"com.arsdigita.cms.loader.section_names",
|
|
Parameter.REQUIRED,
|
|
new String[]{"content"});
|
|
/**
|
|
* 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 Workspace
|
|
ApplicationType appType = loadWorkspaceApplicationType();
|
|
setupDefaultWorkspaceApplicationInstance(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 Workspace 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 loadWorkspaceApplicationType() {
|
|
s_log.debug("Creating CMS Workspace...");
|
|
|
|
/*
|
|
* 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(Workspace.INSTANCE_NAME,
|
|
Workspace.BASE_DATA_OBJECT_TYPE);
|
|
|
|
type.setDescription("The content center workspace for content creators.");
|
|
type.save();
|
|
|
|
s_log.debug("CMS Workspace type created.");
|
|
return type;
|
|
}
|
|
|
|
/**
|
|
* Instantiates the Workspace 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 setupDefaultWorkspaceApplicationInstance(
|
|
ApplicationType workspaceType) {
|
|
|
|
// 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 Workspace instance ...");
|
|
Workspace app = (Workspace) Application.createApplication(
|
|
Workspace.BASE_DATA_OBJECT_TYPE, // type
|
|
Workspace.PACKAGE_KEY, // url fragment
|
|
Workspace.INSTANCE_NAME, // title
|
|
null); // parent
|
|
app.setDescription("The default CMS workspace instance.");
|
|
app.save();
|
|
|
|
s_log.debug("CMS Workspace instance " + Workspace.PACKAGE_KEY + " created.");
|
|
s_log.debug("Done loading CMS Workspace.");
|
|
}
|
|
|
|
/**
|
|
* 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.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.
|
|
*
|
|
* <b>UDCT Copyright</b>
|
|
* <pre>
|
|
* <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>
|
|
* </pre>
|
|
*
|
|
* @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.");
|
|
}
|
|
}
|