Java tutorial
/* * #%L * Alfresco Repository * %% * Copyright (C) 2005 - 2016 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of * the paid license agreement will prevail. Otherwise, the software is * provided under the following open source license terms: * * Alfresco 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 3 of the License, or * (at your option) any later version. * * Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>. * #L% */ package org.alfresco.repo.admin.patch.impl; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.importer.ImporterBootstrap; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.cmr.view.ImporterBinding.UUID_BINDING; import org.alfresco.service.descriptor.Descriptor; import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.util.PropertyCheck; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.surf.util.I18NUtil; /** * A Patch based importer which creates and populates * a site based on the supplied data * * @author Nick Burch */ public class SiteLoadPatch extends AbstractPatch { public static final String PROPERTIES_USERS = "users"; public static final String PROPERTIES_PEOPLE = "people"; public static final String PROPERTIES_GROUPS = "groups"; public static final String PROPERTIES_CONTENTS = "contents"; private static final Map<String, String> DEFAULT_PATHS = new HashMap<String, String>(); static { DEFAULT_PATHS.put(PROPERTIES_USERS, "/${alfresco_user_store.system_container.childname}/${alfresco_user_store.user_container.childname}"); DEFAULT_PATHS.put(PROPERTIES_PEOPLE, "/${system.system_container.childname}/${system.people_container.childname}"); DEFAULT_PATHS.put(PROPERTIES_GROUPS, null); DEFAULT_PATHS.put(PROPERTIES_CONTENTS, "/${spaces.company_home.childname}/${spaces.sites.childname}"); } private static final String MSG_SITE_ALREADY_EXISTS = "patch.siteLoadPatch.exists"; private static final String MSG_NO_BOOTSTRAP_VIEWS_GIVEN = "patch.siteLoadPatch.noBootstrapViews"; private static final String MSG_SITE_CREATED = "patch.siteLoadPatch.result"; private static final String MSG_SITE_NOT_CREATED = "patch.siteLoadPatch.siteNotCreated"; private static final String MSG_SITE_LOAD_DISABLED = "patch.siteLoadPatch.siteLoadDisabled"; // Logger private static final Log logger = LogFactory.getLog(SiteLoadPatch.class); private AuthorityService authorityService; private BehaviourFilter behaviourFilter; private SiteService siteService; private DescriptorService descriptorService; private String siteName; private ImporterBootstrap spacesBootstrap; private ImporterBootstrap usersBootstrap; private Map<String, Properties> bootstrapViews; private Boolean disabled = false; public SiteLoadPatch() { // We do need to run in our own transaction setRequiresTransaction(true); } /** * Sets the name of the site to be bootstrapped. * * @param siteName The short name of the site */ public void setSiteName(String siteName) { this.siteName = siteName; } public void setSpacesBootstrap(ImporterBootstrap spacesBootstrap) { this.spacesBootstrap = spacesBootstrap; } public void setUsersBootstrap(ImporterBootstrap usersBootstrap) { this.usersBootstrap = usersBootstrap; } /** * Sets the details of the bootstraps to perform */ public void setBootstrapViews(Map<String, Properties> bootstrapViews) { this.bootstrapViews = bootstrapViews; } /** * Sets the Site Service to be used for importing into * * @param siteService The Site Service */ public void setSiteService(SiteService siteService) { this.siteService = siteService; } /** * Sets the Authority Service to be used for groups and people * * @param authorityService The Authority Service */ public void setAuthorityService(AuthorityService authorityService) { this.authorityService = authorityService; } /** * @param descriptorService the descriptorService to set */ public void setDescriptorService(DescriptorService descriptorService) { this.descriptorService = descriptorService; } public void setBehaviourFilter(BehaviourFilter behaviourFilter) { this.behaviourFilter = behaviourFilter; } public void setDisabled(boolean disabled) { this.disabled = disabled; } public boolean isDisabled() { return disabled; } @Override protected void checkProperties() { super.checkProperties(); PropertyCheck.mandatory(this, "siteService", siteService); PropertyCheck.mandatory(this, "nodeService", nodeService); PropertyCheck.mandatory(this, "siteName", siteName); } @Override protected String applyInternal() throws Exception { //skip sites that we don't want imported automatically if (isDisabled()) { if (logger.isDebugEnabled()) { logger.debug("Load of site \"" + siteName + "\" is disabled."); } return I18NUtil.getMessage(MSG_SITE_LOAD_DISABLED, siteName); } AuthenticationUtil.pushAuthentication(); try { // The site service is funny about permissions, // so even though we're running as the system we // still need to identify us as the admin user AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); return applyInternalImpl(); } finally { AuthenticationUtil.popAuthentication(); } } /** * Load the site in.<br/> * Site will be loaded as admin user. */ private String applyInternalImpl() throws Exception { if (descriptorService != null) { // if the descriptor service is wired up only load the site at install time (and not on upgrade) Descriptor installed = descriptorService.getInstalledRepositoryDescriptor(); Descriptor live = descriptorService.getServerDescriptor(); if (!installed.getVersion().equals(live.getVersion())) { return I18NUtil.getMessage(MSG_SITE_NOT_CREATED, siteName); } } if (bootstrapViews == null || bootstrapViews.size() == 0) { if (logger.isDebugEnabled()) { logger.debug("No Bootstraps given to import from - bootstrap import ignored"); } return I18NUtil.getMessage(MSG_NO_BOOTSTRAP_VIEWS_GIVEN, siteName); } // Is the site already there? // (Run now as we need DB + Security Context) if (siteService.getSite(siteName) != null) { if (logger.isDebugEnabled()) { logger.debug("Site " + siteName + " already exists - bootstrap import ignored"); } return I18NUtil.getMessage(MSG_SITE_ALREADY_EXISTS, siteName); } // If we get here, we're good to go! if (logger.isDebugEnabled()) { logger.debug("Performing bootstrap of site " + siteName); } // Create the site as the admin user SiteInfo site = siteService.createSite(siteName, siteName, siteName, null, SiteVisibility.PUBLIC); // At this point we can go back to being the system AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); // Setup the Importer Bootstrap Beans for (ImporterBootstrap bootstrap : new ImporterBootstrap[] { spacesBootstrap, usersBootstrap }) { bootstrap.setAllowWrite(true); bootstrap.setUseExistingStore(true); bootstrap.setUuidBinding(UUID_BINDING.REPLACE_EXISTING); } // Normally paths aren't given for the views, so supply // the defaults where they weren't for (String type : DEFAULT_PATHS.keySet()) { Properties props = bootstrapViews.get(type); if (props != null && DEFAULT_PATHS.get(type) != null) { if (!props.containsKey("path")) { props.setProperty("path", DEFAULT_PATHS.get(type)); } } } // Load our various bootstraps, in the required order // for things to come in correctly // Load any users requested if (bootstrapViews.containsKey(PROPERTIES_USERS)) { List<Properties> views = new ArrayList<Properties>(1); views.add(bootstrapViews.get(PROPERTIES_USERS)); usersBootstrap.setBootstrapViews(views); usersBootstrap.bootstrap(); } // Load any people requested if (bootstrapViews.containsKey(PROPERTIES_PEOPLE)) { List<Properties> views = new ArrayList<Properties>(1); views.add(bootstrapViews.get(PROPERTIES_PEOPLE)); spacesBootstrap.setBootstrapViews(views); spacesBootstrap.bootstrap(); } // Put people into groups if (bootstrapViews.containsKey(PROPERTIES_GROUPS)) { try { doGroupImport(bootstrapViews.get(PROPERTIES_GROUPS).getProperty("location")); } catch (Throwable t) { throw new AlfrescoRuntimeException("Bootstrap failed", t); } } // Load the Main (ACP) Contents if (bootstrapViews.containsKey(PROPERTIES_CONTENTS)) { // Disable the behaviour which prevents site deletion. behaviourFilter.disableBehaviour(site.getNodeRef(), ContentModel.ASPECT_UNDELETABLE); try { // Clear up the stub content that createSite gave us, first // apply the temporary aspect though to prevent the node from // being archived nodeService.addAspect(site.getNodeRef(), ContentModel.ASPECT_TEMPORARY, null); nodeService.deleteNode(site.getNodeRef()); } finally { behaviourFilter.enableBehaviour(site.getNodeRef(), ContentModel.ASPECT_UNDELETABLE); } // Now load in the real content from the ACP List<Properties> views = new ArrayList<Properties>(1); views.add(bootstrapViews.get(PROPERTIES_CONTENTS)); spacesBootstrap.setBootstrapViews(views); spacesBootstrap.bootstrap(); } return I18NUtil.getMessage(MSG_SITE_CREATED, siteName); } /** * Note - This Could potentially be split out into another Bootstrap class, * but for now is inline to keep things simple */ private void doGroupImport(String location) throws Throwable { File groupFile = ImporterBootstrap.getFile(location); BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(groupFile), "UTF-8")); String line; while ((line = reader.readLine()) != null) { int splitAt = line.indexOf('='); if (splitAt == -1) { logger.warn("Invalid group line " + line); continue; } String user = line.substring(0, splitAt); Set<String> currentGroups = authorityService.getAuthoritiesForUser(user); StringTokenizer groups = new StringTokenizer(line.substring(splitAt + 1), ","); while (groups.hasMoreTokens()) { String group = groups.nextToken(); if (!currentGroups.contains(group)) { authorityService.addAuthority(group, user); if (logger.isDebugEnabled()) { logger.debug("Added user " + user + " to group " + group); } } } } reader.close(); } }