package org.sakaiproject.portal.service; import java.util.List; import java.util.Observable; import java.util.Observer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.alias.api.Alias; import org.sakaiproject.alias.api.AliasService; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.entity.api.Entity; import org.sakaiproject.entity.api.EntityManager; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.event.api.Event; import org.sakaiproject.event.api.EventTrackingService; import org.sakaiproject.exception.IdInvalidException; import org.sakaiproject.exception.IdUsedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SitePage; import org.sakaiproject.site.api.SiteService; /** * When a site is updated we check that all the pages have aliases. * We want to keep existing aliases as they may have been sent to someone in an email. * If the title changes though we should generate a new alias. * Should sort by date as newest alias should be used. * @author buckett * */ public class AliasingSiteAdvisor implements Observer { /** * Configuration parameter for sakai.properties to control if we generate page aliases. */ private static final String PORTAL_USE_PAGE_ALIASES = "portal.use.page.aliases"; private static Log log = LogFactory.getLog(AliasingSiteAdvisor.class); private static String PAGE_ALIAS = Entity.SEPARATOR+ "pagealias"+ Entity.SEPARATOR; private AliasService aliasService; private SiteService siteService; private ServerConfigurationService serverConfigurationService; private EntityManager entityManager; private EventTrackingService eventTrackingService; /** * Maximum length of a page alias. */ private int maxLength; public int getMaxLength() { return maxLength; } public void setMaxLength(int maxLength) { this.maxLength = maxLength; } public void init() { if (serverConfigurationService.getBoolean(PORTAL_USE_PAGE_ALIASES, false)) { log.info("Page aliases will be generated."); // Only want a local observer so the node that performs the site save updates the aliases. getEventTrackingService().addLocalObserver(this); } } public void update(Observable o, Object arg) { if (arg instanceof Event) { Event event = (Event)arg; if (SiteService.SECURE_UPDATE_SITE.equals(event.getEvent()) || SiteService.SECURE_ADD_SITE.equals(event.getEvent())) { Reference ref = entityManager.newReference(event.getResource()); Entity entity = ref.getEntity(); if (entity instanceof Site) { update((Site)entity); } else { log.warn("Couldn't find site that has just been updated: "+ entity); } } } } public void update(Site site) { for (SitePage page : (List<SitePage>)site.getPages()) { List<Alias> aliases = (List<Alias>)aliasService.getAliases(page.getReference()); String shortName = resolvePageName(site, page, page.getTitle()); if (shortName == null || shortName.length() == 0) { continue; } String possibleAlias = PAGE_ALIAS+ page.getSiteId()+ Entity.SEPARATOR+ shortName; boolean exists = false; if (!aliases.isEmpty()) { for (Alias alias: aliases) { if (possibleAlias.equals(alias.getId())) { exists = true; continue; } } } if (!exists) { // Create a new alias. try { aliasService.setAlias(possibleAlias, page.getReference()); } catch (IdUsedException e) { if (log.isDebugEnabled()) { log.debug("Alias already exists for: "+possibleAlias); } } catch (IdInvalidException e) { log.warn("Failed to generate a sensible alias: "+ possibleAlias); } catch (PermissionException e) { // Log and there isn't any point in carrying on. log.warn("Lack of permission to create alias: "+ e.getMessage()); break; } } } } /** * Attempt to generate a short name for the page. This could use tool names. * @param site The site in which the page is. * @param page The page. * @param title The title of the page. * @return */ private String resolvePageName(Site site, SitePage page, String title) { String alias = title.toLowerCase(); alias = alias.replaceAll("[^a-z,0-9,_ ]", ""); // Replace everything but good characters alias = alias.replaceAll(" ", "_"); // Translate spaces to underscores alias = alias.replaceAll("_+", "_"); // Trim multiple underscores to one if (alias.length() > maxLength) // Trim if longer than maxlength { alias = alias.substring(0, maxLength); } if (alias.endsWith("_")) { // Trim trailing underscore alias = alias.substring(0, alias.length()-1); } return alias; } public AliasService getAliasService() { return aliasService; } public void setAliasService(AliasService aliasService) { this.aliasService = aliasService; } public SiteService getSiteService() { return siteService; } public void setSiteService(SiteService siteService) { this.siteService = siteService; } public ServerConfigurationService getServerConfigurationService() { return serverConfigurationService; } public void setServerConfigurationService( ServerConfigurationService serverConfigurationService) { this.serverConfigurationService = serverConfigurationService; } public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } public EntityManager getEntityManager() { return entityManager; } public void setEventTrackingService(EventTrackingService eventTrackingService) { this.eventTrackingService = eventTrackingService; } public EventTrackingService getEventTrackingService() { return eventTrackingService; } }