XSkinService.java
/*
* Copyright (C) 2003-2008 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.services.wcm.skin;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.servlet.ServletContext;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.container.RootContainer.PortalContainerPostCreateTask;
import org.exoplatform.container.RootContainer.PortalContainerInitTask;
import org.exoplatform.portal.resource.SkinConfig;
import org.exoplatform.portal.resource.SkinKey;
import org.exoplatform.portal.resource.SkinService;
import org.exoplatform.portal.resource.SkinVisitor;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.wcm.core.WCMConfigurationService;
import org.exoplatform.services.wcm.portal.LivePortalManagerService;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.gatein.wci.WebApp;
import org.picocontainer.Startable;
/**
* Created by The eXo Platform SAS Author : Hoa.Pham hoa.pham@exoplatform.com
* Apr 9, 2008
*/
public class XSkinService implements Startable {
/* Don't use "-", "_", ":" "#" "%" */
final static String SEPARATOR = "/";
final static String MODULE_NAME_PATTERN = "{repositoryName}"+SEPARATOR+"{portalName}";
final static String MODULE_NAME_REGEXP = "(.*)"+SEPARATOR+"(.*)";
final static String MODULE_PARAM = "moduleName";
final static String SKIN_PARAM = "skinName";
final static String CONTEXT_PARAM = "context";
final static String SITENAME_PARAM = "siteName";
/** The Constant SKIN_PATH_REGEXP. */
public final static String SKIN_PATH_REGEXP = "/(.*)/css/jcr/"+MODULE_NAME_REGEXP+"/(.*)/(.*).css";
/** The Constant SKIN_PATH_PATTERN. */
private final static String SKIN_PATH_PATTERN = "/{docBase}/css/jcr/{moduleName}/(.*)/Stylesheet.css";
/** The log. */
private static final Log LOG = ExoLogger.getLogger(XSkinService.class.getName());
/** The configuration service. */
private WCMConfigurationService configurationService;
/** The skin service. */
private SkinService skinService ;
/** The servlet context. */
private ServletContext servletContext;
/**
* Instantiates a new extended skin service to manage skin for web content.
*
* @param livePortalService the LivePortalManagerService service
* @throws Exception the exception
*/
public XSkinService(LivePortalManagerService livePortalService) throws Exception {
this.skinService = WCMCoreUtils.getService(SkinService.class);
this.skinService.addResourceResolver(new WCMSkinResourceResolver(this.skinService, livePortalService));
this.configurationService = WCMCoreUtils.getService(WCMConfigurationService.class);
this.servletContext = WCMCoreUtils.getService(ServletContext.class);
}
/**
* Gets the active style sheet of the specified web content node
*
* @param webcontent the web content node to get style sheet
* @return the active style sheet
* @throws Exception the exception
*/
public String getActiveStylesheet(Node webcontent) throws Exception {
return WCMCoreUtils.getActiveStylesheet(webcontent);
}
/**
* Update portal skin on modify.
*
* @param portal the portal
* @param cssFile the css file
*
* @throws Exception the exception
*/
public void updatePortalSkinOnModify(Node portal, Node cssFile) throws Exception {
String sharedPortalName = configurationService.getSharedPortalName();
if (sharedPortalName.equals(portal.getName())) {
addSharedPortalSkin(portal);
} else {
addPortalSkin(portal);
}
}
/**
* Update portal skin on remove.
*
* @param portal the portal
* @param cssFile the css file
*
* @throws Exception the exception
*/
public void updatePortalSkinOnRemove(Node portal, Node cssFile) throws Exception {
updatePortalSkinOnModify(portal, cssFile);
}
/**
* Adds the portal skin.
*
* @param portalNode the portal
*
* @throws Exception the exception
*/
private void addPortalSkin(Node portalNode) throws Exception {
String moduleName = createModuleName(portalNode.getName());
String skinPath = StringUtils.replaceOnce(SKIN_PATH_PATTERN, "{moduleName}",moduleName)
.replaceFirst("\\{docBase\\}",
servletContext.getServletContextName());
Iterator<String> iterator = skinService.getAvailableSkinNames().iterator();
if (iterator.hasNext() == false) {
skinPath = StringUtils.replaceOnce(skinPath,"(.*)", "Default");
skinService.invalidateCachedSkin(skinPath);
skinService.addSkin(moduleName, "Default", skinPath);
} else {
while (iterator.hasNext()) {
String skinName = iterator.next();
skinPath = StringUtils.replaceOnce(skinPath,"(.*)",skinName);
skinService.invalidateCachedSkin(skinPath);
skinService.addSkin(moduleName, skinName, skinPath);
}
}
}
/**
* Adds the shared portal skin.
*
* @param portalNode the portal
*
* @throws Exception the exception
*/
private void addSharedPortalSkin(Node portalNode) throws Exception {
String moduleName = createModuleName(portalNode.getName());
String skinPath = StringUtils.replaceOnce(SKIN_PATH_PATTERN, "{moduleName}", moduleName)
.replaceFirst("\\{docBase\\}",
servletContext.getServletContextName());
for (Iterator<String> iterator = skinService.getAvailableSkinNames().iterator(); iterator.hasNext();) {
String skinName = iterator.next();
skinPath = StringUtils.replaceOnce(skinPath, "(.*)", skinName);
skinService.invalidateCachedSkin(skinPath);
skinService.addPortalSkin(moduleName, skinName, skinPath);
}
}
/* (non-Javadoc)
* @see org.picocontainer.Startable#start()
*/
public void start() {
/**
* Because all skins are added via {@link PortalContainerInitTask} (which run after services start) in {@link org.exoplatform.portal.resource.GateInSkinConfigDeployer#add(WebApp, URL)}
* And we need to add custom styleSheet after all skins are configured and ready.
* So, we must use {@link PortalContainerPostCreateTask} (it's run after all init tasks executed) for doing that.
*/
final PortalContainerPostCreateTask task = new PortalContainerPostCreateTask() {
public void execute(ServletContext context, PortalContainer portalContainer) {
SessionProvider sessionProvider = SessionProvider.createSystemProvider();
try {
LivePortalManagerService livePortalManagerService = portalContainer.getComponentInstanceOfType(LivePortalManagerService.class);
List<Node> livePortals = livePortalManagerService.getLivePortals(sessionProvider);
for (Node portal : livePortals) {
addPortalSkin(portal);
}
Node sharedPortal = livePortalManagerService.getLiveSharedPortal(sessionProvider);
addSharedPortalSkin(sharedPortal);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("Exception when start XSkinService", e);
}
} finally {
sessionProvider.close();
}
}
};
PortalContainer.addInitTask(this.servletContext, task, null);
}
/* (non-Javadoc)
* @see org.picocontainer.Startable#stop()
*/
public void stop() {
}
static String createModuleName(String siteName){
String repoName;
try{
repoName = WCMCoreUtils.getRepository().getConfiguration().getName();
}catch(NullPointerException e){
repoName = WCMCoreUtils.getService(RepositoryService.class).getConfig().getDefaultRepositoryName();
}
String moduleName = StringUtils.replaceOnce(MODULE_NAME_PATTERN, "{repositoryName}", repoName);
moduleName = StringUtils.replaceOnce(moduleName,"{portalName}",siteName);
return moduleName;
}
static Map<String,String> getSkinParams(String path){
if (!path.matches(SKIN_PATH_REGEXP)) return null;
String moduleName;
String skinName;
String siteName;
String context;
String[] elements = path.split("/");
if (XSkinService.SEPARATOR.equals("/")){
context = elements[4];
siteName = elements[5];
skinName = elements[6];
}else{
context = elements[4].split(XSkinService.SEPARATOR)[0];
siteName = elements[4].split(XSkinService.SEPARATOR)[1];
skinName = elements[5];
}
moduleName = StringUtils.replaceOnce(MODULE_NAME_PATTERN, "{repositoryName}", context);
moduleName = StringUtils.replaceOnce(moduleName,"{portalName}",siteName);
Map<String,String> params = new HashMap<String,String>();
params.put(MODULE_PARAM, moduleName);
params.put(SKIN_PARAM, skinName);
params.put(SITENAME_PARAM, siteName);
params.put(CONTEXT_PARAM, context);
return params;
}
}