/*
* Copyright (C) 2003-2009 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.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.servlet.ServletContext;
import org.exoplatform.commons.xml.DocumentSource;
import org.exoplatform.component.test.web.ServletContextImpl;
import org.exoplatform.component.test.web.WebAppImpl;
import org.exoplatform.portal.resource.SkinConfig;
import org.exoplatform.portal.resource.SkinService;
import org.exoplatform.portal.resource.config.xml.SkinConfigParser;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.wcm.BaseWCMTestCase;
import org.exoplatform.services.wcm.core.WCMConfigurationService;
import org.exoplatform.services.wcm.portal.LivePortalManagerService;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.exoplatform.test.mocks.servlet.MockServletRequest;
import org.exoplatform.web.ControllerContext;
import org.exoplatform.web.controller.QualifiedName;
import org.exoplatform.web.controller.metadata.DescriptorBuilder;
import org.exoplatform.web.controller.router.Router;
import org.exoplatform.web.controller.router.RouterConfigException;
/**
* The Class TestXJavaScriptService.
*
* Created by The eXo Platform SAS
* Author : Ngoc.Tran
* ngoc.tran@exoplatform.com
* July 21, 2008
*/
public class TestXSkinService extends BaseWCMTestCase {
/** The skin service. */
private XSkinService skinService;
protected ControllerContext controllerCtx;
private static ServletContext mockServletContext;
protected static MockResourceResolver resResolver;
SkinService configService;
/** The Constant WEB_CONTENT_NODE_NAME. */
private static final String WEB_CONTENT_NODE_NAME = "webContent";
private Node documentNode;
private Node sharedCssNode;
public void setUp() throws Exception {
super.setUp();
applySystemSession();
documentNode = (Node) session.getItem("/sites content/live/classic/documents");
sharedCssNode = (Node) session.getItem("/sites content/live/classic/css");
skinService = getService(XSkinService.class);
configService = getService(SkinService.class);
controllerCtx = getControllerContext();
URL base = TestXSkinService.class.getClassLoader().getResource("mockwebapp");
File f = new File(base.toURI());
mockServletContext = new ServletContextImpl(f, "/mockwebapp", "mockwebapp");
configService.registerContext(new WebAppImpl(mockServletContext, Thread.currentThread().getContextClassLoader()));
resResolver = new MockResourceResolver();
configService.addResourceResolver(resResolver);
URL url = mockServletContext.getResource("/gatein-resources.xml");
SkinConfigParser.processConfigResource(DocumentSource.create(url), configService, mockServletContext);
}
/**
* Test get active Stylesheet_01.
*
* When parameter input is null
*/
public void testGetActiveStylesheet_01() {
try {
skinService.getActiveStylesheet(null);
fail();
} catch (Exception e) {
assertNotNull(e.getStackTrace());
}
}
/**
* Test get active Stylesheet_02.
*
* When node input node type is not exo:webcontent.
*/
public void testGetActiveStylesheet_02() {
try {
Node nodeInput = documentNode.addNode(WEB_CONTENT_NODE_NAME);
session.save();
String cssData = skinService.getActiveStylesheet(nodeInput);
assertEquals("", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test get active Stylesheet_03.
*
* When node input is exo:webcontent and have some child node but does not content mixin type.
*/
public void testGetActiveStylesheet_03() {
try {
Node webContent = documentNode.addNode(WEB_CONTENT_NODE_NAME, "exo:webContent");
webContent.setProperty("exo:title", WEB_CONTENT_NODE_NAME);
session.save();
String cssData = skinService.getActiveStylesheet(webContent);
assertEquals("", cssData);
} catch(Exception e) {
e.printStackTrace();
fail();
}
}
/**
* Test get active Stylesheet_04.
*
* Child node have properties normal and value of exo:active is:
* - "exo:active": false
*/
public void testGetActiveStylesheet_04() {
try {
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
Node cssNode = webContent.getNode("css").getNode("default.css");
cssNode.setProperty("exo:active", false);
session.save();
String cssData = skinService.getActiveStylesheet(webContent);
assertEquals("", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test get active Stylesheet_05.
*
* Child node have properties normal and value of jcr:mimeType is:
* - "jcr:mimeType": text/css
*/
public void testGetActiveStylesheet_05() {
try {
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
Node jsNode = webContent.getNode("css").getNode("default.css");
Node jsContent = jsNode.getNode("jcr:content");
jsContent.setProperty("jcr:mimeType", "text/css");
session.save();
String cssData = skinService.getActiveStylesheet(webContent);
assertEquals("This is the default.css file.", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test get active Stylesheet_06.
*
* Child node have properties normal and value of jcr:data is ""
*/
public void testGetActiveStylesheet_06() {
try {
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, "", null);
String cssData = skinService.getActiveStylesheet(webContent);
assertEquals("", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test get active Stylesheet_07.
*
* In case normal
*/
public void testGetActiveStylesheet_07() {
try {
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
String cssData = skinService.getActiveStylesheet(webContent);
assertEquals("This is the default.css file.", cssData);
} catch (Exception e) {
fail();
}
}
/**
* Test update portal Skin on modify_01.
* When node input is null.
*/
public void testUpdatePortalSkinOnModify_01() {
try {
Node portal = findPortalNode(sessionProvider, documentNode);
createSharedCssNode(sharedCssNode);
skinService.updatePortalSkinOnModify(portal, null);
} catch(Exception e) {
assertNotNull(e.getStackTrace());
}
}
/**
* Test update portal Skin on modify_02.
* When Node portal input is null.
*/
public void testUpdatePortalSkinOnModify_02() {
try {
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
Node jsNode = webContent.getNode("css").getNode("default.css");
skinService.updatePortalSkinOnModify(null, jsNode);
} catch(Exception e) {
assertNotNull(e.getStackTrace());
}
}
/**
* Test update portal Skin on modify_03.
* When Node input does not cssFile.
*/
public void testUpdatePortalSkinOnModify_03() {
try {
Node portal = this.findPortalNode(sessionProvider, documentNode);
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
createSharedCssNode(sharedCssNode);
Node jsFolder = webContent.getNode("css");
skinService.updatePortalSkinOnModify(portal, jsFolder);
} catch(Exception e) {
assertNotNull(e.getStackTrace());
}
}
/**
* Test update portal Skin on modify_04.
* When node input have jcr:data is "".
*/
public void testUpdatePortalSkinOnModify_04() {
try {
Node portal = findPortalNode(sessionProvider, documentNode);
SkinService configService = null;
Node webcontent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
Node cssNode = webcontent.getNode("css").getNode("default.css");
createSharedCssNode(sharedCssNode);
configService = getService(SkinService.class);
configService.addSkin(webcontent.getName(), "Default", "");
skinService.updatePortalSkinOnModify(portal, cssNode);
session.save();
String resource = "/portal/css/jcr/"+XSkinService.createModuleName("classic")+"/Default/Stylesheet.css";
String url = newSimpleSkin(resource).createURL(controllerCtx).toString();
resResolver.addResource(resource, "foo");
assertEquals("This is the sharedJsFile.css file.", configService.getCSS(newControllerContext(getRouter(), url), true));
// String cssData = configService.getCSS("/portal/css/jcr/classic/Default/Stylesheet.css");
// assertEquals("This is the sharedJsFile.css file.", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test update portal Skin on modify_05.
* When node input have jcr:data is "Test XSkin Service".
*/
public void testUpdatePortalSkinOnModify_05() {
try {
Node portal = findPortalNode(sessionProvider, documentNode);
SkinService configService = null;
Node webcontent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
Node cssNode = webcontent.getNode("css").getNode("default.css");
createSharedCssNode(sharedCssNode);
configService = getService(SkinService.class);
configService.addSkin("", "Default", "");
skinService.updatePortalSkinOnModify(portal, cssNode);
session.save();
String resource = "/portal/css/jcr/"+XSkinService.createModuleName("classic")+"/Default/Stylesheet.css";
String url = newSimpleSkin(resource).createURL(controllerCtx).toString();
resResolver.addResource(resource, "foo");
assertEquals("This is the sharedJsFile.css file.", configService.getCSS(newControllerContext(getRouter(), url), true));
// String cssData = configService.getCSS("/portal/css/jcr/classic/Default/Stylesheet.css");
// assertEquals("This is the sharedJsFile.css file.", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test update portal Skin on remove_01.
* When node input is null.
*/
public void testUpdatePortalSkinOnRemove_01() {
try {
Node portal = findPortalNode(sessionProvider, documentNode);
createSharedCssNode(sharedCssNode);
skinService.updatePortalSkinOnRemove(portal, null);
} catch(Exception e) {
assertNotNull(e.getStackTrace());
}
}
/**
* Test update portal Skin on remove_02.
* When Node portal input is null.
*/
public void testUpdatePortalSkinOnRemove_02() {
try {
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
Node cssNode = webContent.getNode("css").getNode("default.css");
skinService.updatePortalSkinOnRemove(null, cssNode);
fail();
} catch(Exception e) {
assertNotNull(e.getStackTrace());
}
}
/**
* Test update portal Skin on remove_03.
* When Node input does not cssFile.
*/
public void testUpdatePortalSkinOnRemove_03() {
try {
Node portal = findPortalNode(sessionProvider, documentNode);
Node webContent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, null, null);
createSharedCssNode(sharedCssNode);
Node cssFolder = webContent.getNode("css");
skinService.updatePortalSkinOnRemove(portal, cssFolder);
} catch(Exception e) {
assertNotNull(e);
}
}
/**
* Test update portal Skin on remove_04.
* When node input have jcr:data is "".
*/
public void testUpdatePortalSkinOnRemove_04() {
try {
Node portal = findPortalNode(sessionProvider, documentNode);
SkinService configService = null;
Node webcontent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, "", null);
Node cssNode = webcontent.getNode("css").getNode("default.css");
createSharedCssNode(sharedCssNode);
configService = getService(SkinService.class);
configService.removeSkin(XSkinService.createModuleName(portal.getName()), "Default");
skinService.updatePortalSkinOnRemove(portal, cssNode);
session.save();
String resource = "/portal/css/jcr/"+XSkinService.createModuleName("classic")+"/Default/Stylesheet.css";
String url = newSimpleSkin(resource).createURL(controllerCtx).toString();
resResolver.addResource(resource, "foo");
assertEquals("This is the sharedJsFile.css file.", configService.getCSS(newControllerContext(getRouter(), url), true));
// String cssData = configService.getCSS("/portal/css/jcr/classic/Default/Stylesheet.css");
// assertEquals("This is the sharedJsFile.css file.", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test update portal Skin on remove_05.
* When node input have jcr:data is "Test XSkin Service".
*/
public void testUpdatePortalSkinOnRemove_05() {
try {
Node portal = findPortalNode(sessionProvider, documentNode);
SkinService configService = null;
Node webcontent = createWebcontentNode(documentNode, WEB_CONTENT_NODE_NAME, null, "Test XSkin Service.", null);
Node cssNode = webcontent.getNode("css").getNode("default.css");
createSharedCssNode(sharedCssNode);
session.save();
configService = getService(SkinService.class);
configService.invalidateCachedSkin("/portal/css/jcr/"+XSkinService.createModuleName("classic")+"/Default/Stylesheet.css");
configService.addSkin(portal.getName(), "Default", "");
skinService.updatePortalSkinOnRemove(portal, cssNode);
session.save();
String resource = "/portal/css/jcr/"+XSkinService.createModuleName("classic")+"/Default/Stylesheet.css";
String url = newSimpleSkin(resource).createURL(controllerCtx).toString();
resResolver.addResource(resource, "foo");
assertEquals("This is the sharedJsFile.css file.", configService.getCSS(newControllerContext(getRouter(), url), true));
// String cssData = configService.getCSS("/portal/css/jcr/classic/Default/Stylesheet.css");
// assertEquals("This is the sharedJsFile.css file.", cssData);
} catch(Exception e) {
fail();
}
}
/**
* Test update portal Skin on remove_07.
* When portal node is shared portal.
*/
public void testUpdatePortalSkinOnRemove_07() {
try {
WCMConfigurationService configurationService = WCMCoreUtils.getService(WCMConfigurationService.class);;
LivePortalManagerService livePortalManagerService = getService(LivePortalManagerService.class);
String sharedPortalName = configurationService.getSharedPortalName();
Node portal = livePortalManagerService.getLivePortal(sessionProvider, sharedPortalName);
SkinService configService = getService(SkinService.class);
Node sharedNode = (Node) session.getItem("/sites content/live/" + sharedPortalName + "/css");
createSharedCssNode(sharedNode);
configService.invalidateCachedSkin("/portal/css/jcr/" + XSkinService.createModuleName(sharedPortalName) + "/Default/Stylesheet.css");
skinService.updatePortalSkinOnRemove(portal, null);
session.save();
String resource = "/portal/css/jcr/" + XSkinService.createModuleName(sharedPortalName) + "/Default/Stylesheet.css";
String url = newSimpleSkin(resource).createURL(controllerCtx).toString();
resResolver.addResource(resource, "foo");
assertEquals("This is the sharedJsFile.css file.", configService.getCSS(newControllerContext(getRouter(), url), true));
// String cssData = configService.getCSS("/portal/css/jcr/" + sharedPortalName + "/Default/Stylesheet.css");
// assertEquals("This is the sharedJsFile.css file.", cssData);
} catch(Exception e) {
fail();
}
}
public void testPortalSkins() {
try {
WCMConfigurationService configurationService = WCMCoreUtils.getService(WCMConfigurationService.class);;
LivePortalManagerService livePortalManagerService = getService(LivePortalManagerService.class);
String sharedPortalName = configurationService.getSharedPortalName();
Node portal = livePortalManagerService.getLivePortal(sessionProvider, sharedPortalName);
SkinService configService = getService(SkinService.class);
Node sharedNode = (Node) session.getItem("/sites content/live/" + sharedPortalName + "/css");
createSharedCssNode(sharedNode);
configService.invalidateCachedSkin("/portal/css/jcr/" + XSkinService.createModuleName(sharedPortalName) + "/Default/Stylesheet.css");
skinService.updatePortalSkinOnModify(portal,sharedNode);
session.save();
Collection<SkinConfig> skins = configService.getPortalSkins("Default");
assertEquals(skins.size(),1);
for (SkinConfig skin : skins){
String url = skin.createURL(controllerCtx).toString();
resResolver.addResource(url, "foo");
assertEquals("This is the sharedJsFile.css file.", configService.getCSS(newControllerContext(getRouter(), url), true));
}
} catch(Exception e) {
fail();
}
}
/* (non-Javadoc)
* @see junit.framework.TestCase#tearDown()
*/
public void tearDown() throws Exception {
Node sharedPortalNode = (Node) session.getItem("/sites content/live/shared/css");
NodeIterator nodeIterator = documentNode.getNodes();
NodeIterator cssNodeIterator = sharedCssNode.getNodes();
NodeIterator sharedIterator = sharedPortalNode.getNodes();
while(nodeIterator.hasNext()) {
nodeIterator.nextNode().remove();
}
while(cssNodeIterator.hasNext()) {
cssNodeIterator.nextNode().remove();
}
while(sharedIterator.hasNext()) {
sharedIterator.nextNode().remove();
}
session.save();
}
private Node findPortalNode(SessionProvider sessionProvider, Node child) throws Exception{
LivePortalManagerService livePortalManagerService = getService(LivePortalManagerService.class);
String portalName = null;
for(String portalPath: livePortalManagerService.getLivePortalsPath()) {
if(child.getPath().startsWith(portalPath)) {
portalName = livePortalManagerService.getPortalNameByPath(portalPath);
break;
}
}
if(portalName == null) return null;
return livePortalManagerService.getLivePortal(sessionProvider, portalName);
}
private void createSharedCssNode(Node parentNode) throws Exception {
Node cssNode;
cssNode = parentNode.addNode("sharedJsFile.css", "nt:file");
if (!cssNode.isNodeType("exo:cssFile")) {
cssNode.addMixin("exo:cssFile");
}
cssNode.setProperty("exo:active", true);
cssNode.setProperty("exo:priority", 2);
cssNode.setProperty("exo:sharedCSS", true);
Node cssContent;
try {
cssContent = cssNode.getNode("jcr:content");
} catch (Exception ex) {
cssContent = cssNode.addNode("jcr:content", "nt:resource");
}
cssContent.setProperty("jcr:encoding", "UTF-8");
cssContent.setProperty("jcr:mimeType", "text/css");
cssContent.setProperty("jcr:lastModified", new Date().getTime());
String cssData = "This is the sharedJsFile.css file.";
cssContent.setProperty("jcr:data", cssData);
session.save();
}
Router getRouter() {
Router router;
try {
router = DescriptorBuilder.router().add(
DescriptorBuilder.route("/skins/{gtn:version}/{gtn:resource}{gtn:compress}{gtn:orientation}.css")
.with(DescriptorBuilder.routeParam("gtn:handler").withValue("skin"))
.with(DescriptorBuilder.pathParam("gtn:version").matchedBy("[^/]*").preservePath())
.with(DescriptorBuilder.pathParam("gtn:orientation").matchedBy("-(lt)|-(rt)|").captureGroup(true))
.with(DescriptorBuilder.pathParam("gtn:compress").matchedBy("-(min)|").captureGroup(true))
.with(DescriptorBuilder.pathParam("gtn:resource").matchedBy(".+?").preservePath())).build();
return router;
} catch (RouterConfigException e) {
return null;
}
}
public static ControllerContext newControllerContext(Router router, String requestURI) {
try {
MockServletRequest request = new MockServletRequest(null, new URL("http://localhost" + requestURI), "/portal",
null, false);
String portalPath = request.getRequestURI().substring(request.getContextPath().length());
//
Iterator<Map<QualifiedName, String>> matcher = router.matcher(portalPath, request.getParameterMap());
Map<QualifiedName, String> parameters = null;
if (matcher.hasNext()) {
parameters = matcher.next();
}
return new ControllerContext(null, router, request, null, parameters);
} catch (MalformedURLException e) {
return null;
}
}
ControllerContext getControllerContext() {
try {
return newControllerContext(getRouter());
} catch (Exception e) {
throw new IllegalArgumentException("The controller context is not initialized properly", e);
}
}
public static ControllerContext newControllerContext(Router router) {
return newControllerContext(router, "/portal");
}
public SimpleSkin newSimpleSkin(String uri) {
return new SimpleSkin(configService, "module", null, uri);
}
}