/* * Copyright (C) 2001-2004 Red Hat Inc. 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.bundle; import com.arsdigita.london.terms.Domain; import com.arsdigita.london.terms.importer.Parser; import com.arsdigita.categorization.Category; import com.arsdigita.categorization.RootCategoryCollection; import com.arsdigita.cms.ContentSection; import com.arsdigita.cms.SecurityManager; import com.arsdigita.cms.ui.role.RoleFactory; import com.arsdigita.loader.PackageLoader; import com.arsdigita.kernel.Role; import com.arsdigita.kernel.RoleCollection; import com.arsdigita.kernel.permissions.PrivilegeDescriptor; import com.arsdigita.persistence.DataQuery; import com.arsdigita.runtime.ScriptContext; import com.arsdigita.util.parameter.Parameter; import com.arsdigita.util.parameter.StringArrayParameter; import com.arsdigita.web.Application; import org.apache.log4j.Logger; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; /** * Loader executes nonrecurring at install time and loads (installs and * initializes) the ScientificCMS integration module persistently into database. * * Creates category domains in the terms application according to * configuration files and adds jsp templates to navigation. * * 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 Justin Ross <jross@redhat.com> * @author Peter Boy <pboy@barkhof.uni-bremen.de> * @version $Id: Loader.java 755 2005-09-02 13:42:47Z sskracic $ */ public class Loader extends PackageLoader { /** Logger instance for debugging */ private static final Logger s_log = Logger.getLogger(Loader.class); /** * List of comma separated sets of application instance specifications, * optionally used to create arbitrary custom application instances * according to local sites requirements. * It's the developers / administrators responsibility to ensure all * necessary application types have been created previously. * Example: * "FULL_QUALIFIED_CLASS_NAME : URL : TITLE , * FULL_QUALIFIED_CLASS_NAME : URL : TITLE , * .... , * FULL_QUALIFIED_CLASS_NAME : URL : TITLE " * E.G. * "com.arsdigita.navigation.Navigation:local:Local Navigation" */ private Parameter m_customApplicationInstances = new StringArrayParameter( "com.arsdigita.bundle.loader.custom_app_instances", Parameter.OPTIONAL, null ); /** * Comma separated list of fully qualified filenames, each file containing * a set of Terms domain catagories definitions. These form an initial set * of category tree(s), at minimum for navigation, optionally additional * domains. * Files are stored as part of the jar, so classloader can find them. */ private Parameter m_categoryFiles = new StringArrayParameter( "com.arsdigita.bundle.loader.category_files", Parameter.REQUIRED,new String[]{ "bundle/categories/gen-nav-domain-1.00.xml", "bundle/categories/gen-nav-hierarchy-1.00.xml" } ); /** * List of comma separated sets of domain mappings. * It's the developers / administrators responsibility to ensure all * necessary category domains have been imported previously and are spelled * correctly. The list may contain set for different domain key and/or * different applications and contexts. If an domain key requires several * applications, repeat the key and specify a different application and/or * context * Example: * "DOMAIN_KEY_1 : APP_URL_1 [: CONTEXT_1] , * DOMAIN_KEY_1 : APP_URL_2 [: CONTEXT_1] , * DOMAIN_KEY_2 : APP_URL_1 [: CONTEXT] , * .... , * DOMAIN_KEY_n : APP_URL_n [: CONTEXT_n] " * */ private Parameter m_domainMappings = new StringArrayParameter( "com.arsdigita.bundle.loader.domain_mappings", Parameter.REQUIRED,new String[]{ "STD-NAV:/navigation/", "STD-NAV:/info/", "STD-NAV:/portal/" } ); /** * Constructor */ public Loader() { // Register defined parameters to the context by adding // the parameter to a map of parameters register(m_customApplicationInstances); register(m_categoryFiles); register(m_domainMappings); } public void run(final ScriptContext ctx) { /* Create site specific custom applications instances of arbitrary * type specified by optional configuration parameter. * Typically used to create additional navigation instances for alternativ * navigation tree(s) or additional content sections. */ String[] customApplicationInstances = (String[]) get(m_customApplicationInstances); if ( customApplicationInstances != null) { for (int i = 0 ; i < customApplicationInstances.length ; i++) { final String aCustomApplicationInstance = customApplicationInstances[i]; StringTokenizer tok = new StringTokenizer( aCustomApplicationInstance, ":" ); String type = null; // full qualified class name String url = null; // url fragment (last part) String title = null; // title of new application instance String parent = null; // parent class name for ( int j = 0; tok.hasMoreTokens(); j++ ) { if ( 0 == j ) { type = tok.nextToken(); } else if ( 1 == j ) { url = tok.nextToken(); } else if ( 2 == j ) { title = tok.nextToken(); } else if ( 3 == j ) { parent = tok.nextToken(); } else { parent = null; } } Application.createApplication(type, url, title, null); } } /* Import from the categories definition files: Create Terms domains * and populate them with categories * (alternatively this could be delegated to terms.Loader because it's * all Terms) * Creates one or more Terms domains, but NO domain mapping for navigation. * Therefore, registerDomains is required for /navigation/ otherwise * the systems throws NPE for ccm/navigation. */ String[] files = (String[]) get(m_categoryFiles); final Parser parser = new Parser(); // for each filename in the array of files containing categories for (int i = 0 ; i < files.length ; i++) { final String file = files[i]; if (s_log.isInfoEnabled()) { s_log.info("Process " + file); } /* Import a Terms category domain. */ parser.parse(Thread.currentThread().getContextClassLoader(). getResourceAsStream(file)); } /* Creates domain mappings according to configuration file. By default * at least one domain mapping for standard navigation is created, * otherwise navigation wouldn't work. * IOt is the developers / administrators responsibility that KEY is * existent, i.e. previously importet in the previous step. */ String[] domainMappings = (String[]) get(m_domainMappings); for (int i = 0 ; i < domainMappings.length ; i++) { final String aDomainMapping = domainMappings[i]; StringTokenizer tok = new StringTokenizer( aDomainMapping, ":" ); String key = null; String app = null; String context = null; for ( int j = 0; tok.hasMoreTokens(); j++ ) { if ( 0 == j ) { key = tok.nextToken(); } else if ( 1 == j ) { app = tok.nextToken(); } else if ( 2 == j ) { context = tok.nextToken(); } else { context = null; } } registerDomain(key, app, context); } // registerServicesTemplate("/services/"); wird nicht gebraucht } // end run method // public void registerServicesTemplate(String appURL) { // Application app = Application.retrieveApplicationForPath(appURL); // Assert.exists(app, Application.class); // Category root = Category.getRootForObject(app); // Assert.exists(root, Category.class); // // Template template = Template.create( // "APLAWS Services", // "APLAWS ESD Toolkit Services", // "/packages/navigation/templates/aplaws-services.jsp"); // // new TemplateMapping( template, // root, // Template.DEFAULT_DISPATCHER_CONTEXT, // Template.DEFAULT_USE_CONTEXT ); // } /** * Determines the Terms domain using domainKey as well as the application * instance using appURL and then creates a domain mapping using context * as domain context. * * Uses Package com.arsdigita.london.terms.Domain (!) * * @param domainKey * @param appURL * @param context */ public void registerDomain(String domainKey, String appURL, String context) { if (s_log.isDebugEnabled()) { s_log.debug("Mapping domain " + domainKey + " to app " + appURL + " in context " + context); } /* Determine Domain and Application objects, both MUST exist! */ Domain domain = Domain.retrieve(domainKey); Application app = Application.retrieveApplicationForPath(appURL); /* Create domain mapping */ domain.setAsRootForObject(app, context); /* Create permissions and roles for content-center applications only */ if (app instanceof ContentSection) { RoleCollection coll = ((ContentSection) app).getStaffGroup().getOrderedRoles(); Set adminRoles = new HashSet(); Set categorizeRoles = new HashSet(); while (coll.next()) { Role role = coll.getRole(); final DataQuery privs = RoleFactory.getRolePrivileges( app.getID(), role.getGroup().getID()); while (privs.next()) { String priv = (String) privs.get(RoleFactory.PRIVILEGE); if (priv.equals(SecurityManager.CMS_CATEGORY_ADMIN)) { adminRoles.add(role); } else if (priv.equals(SecurityManager.CMS_CATEGORIZE_ITEMS)) { categorizeRoles.add(role); } } } RootCategoryCollection catCollection = Category.getRootCategories(((ContentSection) app)); while (catCollection.next()) { Iterator adminIter = adminRoles.iterator(); while (adminIter.hasNext()) { ((Role) adminIter.next()).grantPermission(catCollection.getCategory(), PrivilegeDescriptor.ADMIN); } Iterator categorizeIter = categorizeRoles.iterator(); while (categorizeIter.hasNext()) { ((Role) categorizeIter.next()).grantPermission(catCollection.getCategory(), Category.MAP_DESCRIPTOR); } } } } }