ScriptServiceImpl.java
/*
* Copyright (C) 2003-2007 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.cms.scripts.impl;
import groovy.lang.GroovyClassLoader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;
import org.apache.commons.lang.StringUtils;
import org.codehaus.groovy.control.CompilationFailedException;
import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.container.component.ComponentPlugin;
import org.exoplatform.container.configuration.ConfigurationManager;
import org.exoplatform.container.xml.ObjectParameter;
import org.exoplatform.services.cache.CacheService;
import org.exoplatform.services.cms.BasePath;
import org.exoplatform.services.cms.impl.BaseResourceLoaderService;
import org.exoplatform.services.cms.impl.DMSConfiguration;
import org.exoplatform.services.cms.impl.DMSRepositoryConfiguration;
import org.exoplatform.services.cms.impl.ResourceConfig;
import org.exoplatform.services.cms.scripts.CmsScript;
import org.exoplatform.services.cms.scripts.ScriptService;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.config.RepositoryEntry;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.wcm.core.NodetypeConstant;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
public class ScriptServiceImpl extends BaseResourceLoaderService implements ScriptService, EventListener {
private GroovyClassLoader groovyClassLoader_ ;
List<ScriptPlugin> plugins_ = new ArrayList<ScriptPlugin>() ;
private DMSConfiguration dmsConfiguration_;
private static final Log LOG = ExoLogger.getLogger(ScriptServiceImpl.class.getName());
private Set<String> configuredScripts_;
/**
* Constructor method
* Init repositoryService, configurationManager, nodeHierarchyCreator, caService, dmsConfiguration
* @param repositoryService RepositoryService
* @param cservice ConfigurationManager
* @param nodeHierarchyCreator NodeHierarchyCreator
* @param cacheService CacheService
* @param dmsConfiguration DMSConfiguration
* @throws Exception
*/
public ScriptServiceImpl(RepositoryService repositoryService, ConfigurationManager cservice,
NodeHierarchyCreator nodeHierarchyCreator, CacheService cacheService,
DMSConfiguration dmsConfiguration) throws Exception {
super(cservice, nodeHierarchyCreator, repositoryService, cacheService, dmsConfiguration);
groovyClassLoader_ = createGroovyClassLoader();
repositoryService_ = repositoryService ;
nodeHierarchyCreator_ = nodeHierarchyCreator ;
dmsConfiguration_ = dmsConfiguration;
}
/**
* {@inheritDoc}
*/
public void start() {
try {
initPlugins();
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("Unexpected error", e);
}
}
}
/**
* add ScriptPlugin
* @param plugin ComponentPlugin
* @see ScriptPlugin
* @see ComponentPlugin
*/
public void addScriptPlugin(ComponentPlugin plugin) {
if(plugin instanceof ScriptPlugin) {
plugins_.add((ScriptPlugin)plugin) ;
}
}
/**
* init Plugin
* @see Session
* @see ScriptPlugin
* @see RepositoryEntry
* @see DMSRepositoryConfiguration
* @see ObservationManager
* @throws Exception
*/
private void initPlugins() throws Exception{
configuredScripts_ = new HashSet<String>();
Session session = null ;
String scriptsPath = getBasePath();
for(ScriptPlugin plugin : plugins_) {
String scriptsLocation = plugin.getPredefineScriptsLocation();
if(plugin.getAutoCreateInNewRepository()) {
DMSRepositoryConfiguration dmsRepoConfig = null;
dmsRepoConfig = dmsConfiguration_.getConfig();
session = repositoryService_.getCurrentRepository().getSystemSession(dmsRepoConfig.getSystemWorkspace());
Iterator<ObjectParameter> iter = plugin.getScriptIterator() ;
while(iter.hasNext()) {
ResourceConfig resourceConfig = (ResourceConfig) iter.next().getObject();
init(session,resourceConfig,scriptsLocation);
addConfigScripts(resourceConfig);
}
ObservationManager obsManager = session.getWorkspace().getObservationManager();
obsManager.addEventListener(this, Event.PROPERTY_CHANGED, scriptsPath, true, null, null, true);
session.save();
session.logout();
}
ManageableRepository mRepository = repositoryService_.getCurrentRepository();
DMSRepositoryConfiguration dmsDefaultRepoConfig = dmsConfiguration_.getConfig();
session = mRepository.getSystemSession(dmsDefaultRepoConfig.getSystemWorkspace()) ;
Iterator<ObjectParameter> iter = plugin.getScriptIterator() ;
while(iter.hasNext()) {
init(session,(ResourceConfig) iter.next().getObject(),scriptsLocation) ;
}
ObservationManager obsManager = session.getWorkspace().getObservationManager();
obsManager.addEventListener(this, Event.PROPERTY_CHANGED, scriptsPath, true, null, null, true);
session.save();
session.logout();
}
}
/**
* get Base Script Path
* @see NodeHierarchyCreator
* @return String
*/
protected String getBasePath() { return nodeHierarchyCreator_.getJcrPath(BasePath.CMS_SCRIPTS_PATH); }
/**
* {@inheritDoc}
*/
public void initRepo() throws Exception {
configuredScripts_ = new HashSet<String>();
ManageableRepository mRepository = repositoryService_.getCurrentRepository();
String scriptsPath = getBasePath();
DMSRepositoryConfiguration dmsRepoConfig = dmsConfiguration_.getConfig();
Session session = mRepository.getSystemSession(dmsRepoConfig.getSystemWorkspace()) ;
for(ScriptPlugin plugin : plugins_) {
if(!plugin.getAutoCreateInNewRepository()) continue ;
String scriptsLocation = plugin.getPredefineScriptsLocation();
Iterator<ObjectParameter> iter = plugin.getScriptIterator() ;
while(iter.hasNext()) {
ResourceConfig resourceConfig = (ResourceConfig) iter.next().getObject();
init(session, resourceConfig,scriptsLocation);
addConfigScripts(resourceConfig);
}
ObservationManager obsManager = session.getWorkspace().getObservationManager();
obsManager.addEventListener(this, Event.PROPERTY_CHANGED, scriptsPath, true, null, null, true);
}
session.save();
session.logout();
}
/**
* {@inheritDoc}
*/
public Node getECMScriptHome(SessionProvider provider) throws Exception {
Session session = getSession(provider);
return getNodeByAlias(BasePath.ECM_EXPLORER_SCRIPTS,session);
}
/**
* {@inheritDoc}
*/
@Override
public List<Node> getECMActionScripts(SessionProvider provider) throws Exception {
Session session = getSession(provider);
return getScriptList(BasePath.ECM_ACTION_SCRIPTS, session);
}
/**
* {@inheritDoc}
*/
@Override
public List<Node> getECMInterceptorScripts(SessionProvider provider) throws Exception {
Session session = getSession(provider);
return getScriptList(BasePath.ECM_INTERCEPTOR_SCRIPTS, session);
}
/**
* {@inheritDoc}
*/
@Override
public List<Node> getECMWidgetScripts(SessionProvider provider) throws Exception {
Session session = getSession(provider);
return getScriptList(BasePath.ECM_WIDGET_SCRIPTS,session);
}
/**
* {@inheritDoc}
*/
@Override
public String getBaseScriptPath() throws Exception {
return getBasePath() ;
}
/**
* {@inheritDoc}}
*/
@Override
public String getScriptAsText(Node script) throws Exception {
return script.getNode(NodetypeConstant.JCR_CONTENT).getProperty(NodetypeConstant.JCR_DATA).getString();
}
/**
* {@inheritDoc}
*/
@Override
public synchronized CmsScript getScript(String scriptName) throws Exception {
CmsScript scriptObject = resourceCache_.get(scriptName);
if (scriptObject != null) return scriptObject;
ExoContainer container = ExoContainerContext.getCurrentContainer() ;
try {
scriptObject = (CmsScript) container.getComponentInstance(scriptName);
if(scriptObject !=null ) {
resourceCache_.put(scriptName, scriptObject) ;
return scriptObject;
}
} catch (NoClassDefFoundError e) {
if (LOG.isWarnEnabled()) {
LOG.warn(e.getMessage());
}
}
groovyClassLoader_ = createGroovyClassLoader();
Class scriptClass = groovyClassLoader_.loadClass(scriptName) ;
container.registerComponentImplementation(scriptName, scriptClass);
scriptObject = (CmsScript) container.getComponentInstance(scriptName);
resourceCache_.put(scriptName, scriptObject) ;
return scriptObject;
}
/**
* {@inheritDoc}
*/
@Override
public void addScript(String name, String text, SessionProvider provider) throws Exception {
addScript(name, name, text, provider);
}
/**
* {@inheritDoc}
*/
@Override
public void addScript(String name, String description, String text, SessionProvider provider) throws Exception {
Node resourcesHome = getResourcesHome(provider);
InputStream in = new ByteArrayInputStream(text.getBytes());
addResource(resourcesHome, name, description, in);
removeFromCache(name) ;
}
/**
* {@inheritDoc}
*/
@Override
public void removeScript(String scriptName, SessionProvider provider) throws Exception {
removeResource(scriptName, provider);
removeFromCache(scriptName) ;
}
/**
* Get ScriptHome
* @param scriptAlias String
* The alias of script
* @param session Session
* @see NodeHierarchyCreator
* @return
* @throws Exception
*/
private Node getScriptHome(String scriptAlias, Session session) throws Exception {
String path = nodeHierarchyCreator_.getJcrPath(scriptAlias) ;
return (Node)session.getItem(path);
}
/**
* get Script List with the following param
* @param scriptAlias String
* The alias of script
* @param session Session
* @see NodeHierarchyCreator
* @return
* @throws Exception
*/
private List<Node> getScriptList(String scriptAlias,Session session) throws Exception {
List<Node> scriptList = new ArrayList<Node>() ;
Node scriptHome = getScriptHome(scriptAlias,session) ;
for(NodeIterator iter = scriptHome.getNodes(); iter.hasNext() ;) {
scriptList.add(iter.nextNode()) ;
}
return scriptList;
}
/**
* remove From Cache
* @param scriptName String
* The name of script
* @see ExoContainer
* @see ExoContainerContext
*/
@Override
protected void removeFromCache(String scriptName){
try{
Object cachedobject = resourceCache_.get(scriptName);
if (cachedobject != null) {
resourceCache_.remove(scriptName) ;
ExoContainer container = ExoContainerContext.getCurrentContainer();
container.unregisterComponent(scriptName);
}
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn(e.getMessage());
}
}
}
/**
* onEvent
* @param events EventIterator
* @see Session
* @see DMSRepositoryConfiguration
* @see ManageableRepository
*/
@Override
public void onEvent(EventIterator events) {
while (events.hasNext()) {
Event event = events.nextEvent();
String path = null;
Session jcrSession = null ;
try {
path = event.getPath();
DMSRepositoryConfiguration dmsRepoConfig = null;
try {
ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
dmsRepoConfig = dmsConfiguration_.getConfig();
jcrSession = manageableRepository.getSystemSession(dmsRepoConfig.getSystemWorkspace());
Property property = (Property) jcrSession.getItem(path);
if ("jcr:data".equals(property.getName())) {
Node node = property.getParent().getParent();
removeFromCache(StringUtils.removeStart(StringUtils.removeStart(node.getPath(), this.getBaseScriptPath()), "/"));
}
jcrSession.logout();
} catch (Exception e) {
jcrSession.logout();
continue ;
}
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("Unexpected error", e);
}
}
}
}
/**
* create Groovy ClassLoader
* @see SessionProvider
* @return
*/
private GroovyClassLoader createGroovyClassLoader() {
ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
return new GroovyClassLoader(parentLoader) {
@SuppressWarnings("unchecked")
protected Class findClass(String className) throws ClassNotFoundException {
String filename = null ;
String nodeName = null ;
if(className.indexOf(":") > -1) {
String[] array = className.split(":") ;
nodeName = array[1] ;
filename = array[1].replace('.', File.separatorChar) + ".groovy";
}else {
nodeName = className ;
filename = className.replace('.', File.separatorChar) + ".groovy";
}
String scriptContent = null;
try {
scriptContent = WCMCoreUtils.getService(BaseResourceLoaderService.class).getResourceAsText(nodeName);
} catch (Exception e) {
throw new ClassNotFoundException("Could not read " + nodeName + ": " + e);
}
try {
return parseClass(scriptContent, filename);
} catch (CompilationFailedException e2) {
throw new ClassNotFoundException("Syntax error in " + filename
+ ": " + e2);
}
}
};
}
/**
* {@inheritDoc}
*/
@Override
public Node getScriptNode(String scriptName,SessionProvider provider) throws Exception {
try {
Node scriptHome = getResourcesHome(provider) ;
return scriptHome.getNode(scriptName) ;
}catch (Exception e) {
return null;
}
}
/**
* Return session of the current repository
* @param provider SessionProvider
* @return
* @see SessionProvider
* @see ManageableRepository
* @see DMSRepositoryConfiguration
* @throws Exception
*/
private Session getSession(SessionProvider provider) throws Exception {
ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
DMSRepositoryConfiguration dmsRepoConfig = dmsConfiguration_.getConfig();
return provider.getSession(dmsRepoConfig.getSystemWorkspace(), manageableRepository);
}
/**
* Get Node By Alias
* @param alias String
* The alias of the specefied node
* @param session Session
* @see NodeHierarchyCreator
* @see Session
* @return
* @throws Exception
*/
private Node getNodeByAlias(String alias,Session session) throws Exception {
String path = nodeHierarchyCreator_.getJcrPath(alias) ;
return (Node)session.getItem(path);
}
/**
* {@inheritDoc}}
*/
@Override
public Set<String> getAllConfiguredScripts() {
return configuredScripts_;
}
private void addConfigScripts(ResourceConfig resourceConfig) {
for (Object obj : resourceConfig.getRessources()) {
if (obj instanceof ResourceConfig.Resource) {
ResourceConfig.Resource resource = (ResourceConfig.Resource)obj;
String name = resource.getName();
if (name.indexOf("/") >=0 ) {
name = name.substring(name.lastIndexOf("/") + 1);
}
configuredScripts_.add(name);
}
}
}
}