/*
* Created on Jan 5, 2005
*/
package com.openedit;
import groovy.util.GroovyScriptEngine;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.openedit.PlugIn;
import org.openedit.repository.Repository;
import org.openedit.repository.filesystem.FileRepository;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.UrlResource;
import com.openedit.config.ScriptPathLoader;
import com.openedit.config.SpringContext;
import com.openedit.page.Page;
import com.openedit.page.manage.PageManager;
import com.openedit.servlet.OpenEditEngine;
import com.openedit.users.UserManager;
import com.openedit.util.PathUtilities;
import com.openedit.util.XmlUtil;
/**
* <p>
* This class contains the core parts of an OpenEdit website. You should not use
* this object if you only need one part of it. This class is responsible for
* loading the Spring beans as defined in the openedit.xml and any applicable
* plugin.xml or pluginoverrides.xml files for extending functionality from
* the core of OpenEdit.
* </p>
* <p>
* This implementation uses a simple Spring BeanFactory to manage the beans.
* </p>
* @see com.openedit.WebServer
* @author cburkey
*
*/
public class BaseWebServer implements WebServer
{
private static final Log log = LogFactory.getLog(WebServer.class);
protected BeanFactory fieldBeanFactory;
protected File fieldRootDirectory;
protected List fieldAllPlugIns;
protected String fieldNodeId;
public String getNodeId()
{
return fieldNodeId;
}
public void setNodeId(String inNodeId)
{
fieldNodeId = inNodeId;
}
public BeanFactory getBeanFactory()
{
// if ( fieldBeanFactory == null )
// {
// synchronized( this ) //the reason for this is when spring is configured it may cause the scheduler to call getBeanFactory() in another thread
// { //We put the synchronized at this level to speed up the loading of web pages
// if ( fieldBeanFactory == null )
// {
// ClassLoader loader = getClass().getClassLoader();
// if( loader == null)
// {
// loader = ClassLoader.getSystemClassLoader();
// }
//
// GenericApplicationContext appContext = new GenericApplicationContext();
// XmlBeanDefinitionReader xbdr = new XmlBeanDefinitionReader(appContext);
// xbdr.setValidating(false);
//// InputStreamResource resource = new InputStreamResource(loader.getResourceAsStream("entermedia.xml"));
//// XmlBeanFactory xmlbeans = new XmlBeanFactory( resource );
//// xmlbeans.setAllowBeanDefinitionOverriding(true);
//// xmlbeans.destroySingletons();
// appContext.getBeanFactory().registerSingleton("WebServer",this);
// appContext.getBeanFactory().registerSingleton("root",getRootDirectory() );
// fieldBeanFactory = xmlbeans;
// }
// }
// }
return fieldBeanFactory;
}
public synchronized void initialize()
{
if ( getRootDirectory() == null)
{
String path = System.getProperty("oe.root.path");
if( path != null)
{
setRootDirectory(new File(path).getAbsoluteFile());
}
}
if ( getRootDirectory() == null)
{
throw new IllegalStateException("Root directory is not defined");
}
//TODO: Look for duplicate openedit jars and try to delete them
try
{
// DefaultListableBeanFactory factory = new DefaultListableBeanFactory()
// {
// public boolean isFactoryBean(String name) throws org.springframework.beans.factory.NoSuchBeanDefinitionException
// {
// String beanName = transformedBeanName(name);
//
// Object beanInstance = getSingleton(beanName, false);
// if (beanInstance != null) {
// boolean ret = (beanInstance instanceof FactoryBean || beanInstance instanceof BeanPostProcessor);
// return ret;
// }
// else if (containsSingleton(beanName)) {
// // null instance registered
// return false;
// }
//
// // No singleton instance found -> check bean definition.
// if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// // No bean definition found in this factory -> delegate to parent.
// return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
// }
//
// return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
// };
// };
SpringContext context = new SpringContext() //factory
{
public org.springframework.core.io.Resource getResource(String location)
{
File custom = new File( getRootDirectory(), "/WEB-INF/src/" + location);
if( custom.exists() )
{
return new FileSystemResource(custom);
}
File folders = new File( getRootDirectory(), "/WEB-INF/base/");
File[] children = folders.listFiles();
if( children != null )
{
for (int i = 0; i < children.length; i++)
{
File script = new File( children[i],"/src/" + location);
if( script.exists() )
{
return new FileSystemResource(script);
}
}
}
return super.getResource(location);
};
};
context.setValidating(false);
ScriptPathLoader pathloader = new ScriptPathLoader();
pathloader.setRoot(getRootDirectory());
List classpathfolders = pathloader.findPaths();
GroovyScriptEngine engine = new GroovyScriptEngine((String[])classpathfolders.toArray(new String[classpathfolders.size()]));
ClassLoader loader = engine.getGroovyClassLoader();
//
// if( loader == null)
// {
// loader = ClassLoader.getSystemClassLoader();
// }
context.setClassLoader(loader);
//InputStreamResource resource = new InputStreamResource(loader.getResourceAsStream("entermedia.xml"));
context.load(new UrlResource(loader.getResource("entermedia.xml")) );
context.getBeanFactory().registerSingleton("WebServer",this);
context.getBeanFactory().registerSingleton("root",getRootDirectory() );
List sorted = getAllPlugIns();
for (Iterator iter = sorted.iterator(); iter.hasNext();)
{
PlugIn plugin = (PlugIn)iter.next();
log.info("Loading " + plugin.getPluginXml().getPath() );
context.load(new UrlResource(plugin.getPluginXml() ) );
}
//Loop over the src folders
File folders = new File( getRootDirectory(), "/WEB-INF/base/");
File[] children = folders.listFiles();
if( children != null )
{
for (int i = 0; i < children.length; i++)
{
File script = new File( children[i],"/src/plugin.xml");
if( script.exists() )
{
context.load(new FileSystemResource(script) );
}
}
}
File custom = new File( getRootDirectory(), "/WEB-INF/src/plugin.xml");
if( custom.exists() )
{
context.load(new FileSystemResource(custom) );
}
File overrideFile = new File( getRootDirectory(), "/WEB-INF/pluginoverrides.xml" ); //TODO: Use a directory of files
if( overrideFile.exists() )
{
context.load(new FileSystemResource(overrideFile));
}
context.refresh();
fieldBeanFactory = context;
} catch ( Throwable ex)
{
log.error("Could not start server: " , ex);
throw new OpenEditRuntimeException(ex);
}
// JarReader reader = new JarReader() //This is for Windows since it locks files. Did not seem to fix the problem
// {
// //Call back
// public void processFile( File inFile)
// {
// loadPluginDefs( inFile );
// }
// };
// reader.processInClasspath("plugin.xml");
// File lib = new File( getRootDirectory(),"WEB-INF/lib");
// reader.processInLibDir(lib,"plugin.xml");
// overridePlugIns();
Thread sh = new Thread( new Runnable() //This is in case the JVM is shut down
{
public void run()
{
try
{
getOpenEditEngine().shutdown();
}
catch (Throwable ex)
{
ex.printStackTrace();
}
}
});
Runtime.getRuntime().addShutdownHook(sh);
reloadMounts();
try
{
Page page = getPageManager().getPage("/WEB-INF/startup.html");
BaseWebPageRequest request = new BaseWebPageRequest();
request.setContentPage(page);
request.setPage(page);
if( page.getPageSettings().exists())
{
getOpenEditEngine().executePathActions(request);
}
if( getModuleManager().contains("PathEventModule") )
{
getModuleManager().execute("PathEventModule.init", request);
}
}
catch( Throwable ex)
{
log.error("Could not initiallize cleanly ", ex);
}
//getBeanFactory().preInstantiateSingletons();
}
public List getAllPlugIns()
{
if( fieldAllPlugIns == null)
{
try
{
ClassLoader loader = getClass().getClassLoader();
if( loader == null)
{
loader = ClassLoader.getSystemClassLoader();
}
Enumeration pluginDefs = loader.getResources( "plugin.xml" ); //This locks jar files on Windows
fieldAllPlugIns = new ArrayList();
Map allplugins = new HashMap();
Map depends = loadDepends();
while( pluginDefs.hasMoreElements() )
{
URL url = (URL) pluginDefs.nextElement();
PlugIn plugin = new PlugIn();
plugin.setPluginXml(url);
plugin.setInstalled(true);
String pluginpath = url.getPath().replace('\\', '/');
pluginpath = PathUtilities.extractDirectoryPath(pluginpath);
plugin.setPlugInPath(pluginpath);
Element depend = (Element)depends.get(pluginpath);
if(depend != null){
String projectname = depend.attributeValue("projectname");
plugin.setId(projectname);
fieldAllPlugIns.add(plugin);
allplugins.put(projectname,plugin);
}
}
populateDependants(allplugins,depends);
//NOW SORT!
DependentComparator compare = new DependentComparator();
Collections.sort(fieldAllPlugIns,compare);
}
catch ( IOException ex)
{
throw new OpenEditException(ex);
}
}
return fieldAllPlugIns;
}
private void populateDependants(Map inPlugins, Map inDepends)
{
for (Iterator iterator = inPlugins.values().iterator(); iterator.hasNext();)
{
PlugIn plugin = (PlugIn) iterator.next();
Element root = (Element)inDepends.get( plugin.getPlugInPath() );
if( root == null)
{
continue; //no dependancy
}
for (Iterator iter = root.elementIterator("depend"); iter.hasNext();)
{
Element child = (Element) iter.next();
String name = child.getTextTrim();
if( name.equals("entermedia"))
{
continue; //Not needed since it is core
}
PlugIn plug = (PlugIn)inPlugins.get(name);
if( plug == null)
{
log.error("Missing dependency:" + name);
}
plugin.addDependsOn(plug);
}
}
}
/**
* Here we sort all the plugins depending on their depandecy tree
* @param pluginurls
* @return
* @throws IOException
*/
protected Map loadDepends() throws IOException
{
ClassLoader loader = getClass().getClassLoader();
if( loader == null)
{
loader = ClassLoader.getSystemClassLoader();
}
Enumeration depends = loader.getResources( "depends.xml" ); //This locks jar files on Windows
XmlUtil util = new XmlUtil();
Map dependslist = new HashMap();
//First load any and all depends that are configured
while( depends.hasMoreElements())
{
URL dependurl = (URL)depends.nextElement();
//PlugIn plugin = (PlugIn)depends.nextElement();
String pluginpath = dependurl.getPath();
pluginpath = pluginpath.replace('\\', '/');
pluginpath = PathUtilities.extractDirectoryPath(pluginpath);
InputStream in = dependurl.openStream();
Element root = util.getXml(in,"UTF-8");
dependslist.put(pluginpath,root);
}
return dependslist;
}
//
// List dependslist = (List)plugindependson.get(project);
// if( dependslist == null)
// {
// dependslist = new ArrayList();
// plugindependson.put(project, dependslist);
// }
// for (Iterator iter = root.elementIterator("depend"); iter.hasNext();)
// {
// Element child = (Element) iter.next();
// String name = child.getTextTrim();
// if( name.equals("openedit"))
// {
// continue; //Not needed since it is core
// }
// dependslist.add(name);
// }
// }
//
// //Make a Map of all of them for searching
// Map plugins = new HashMap();
// for (Iterator iterator = allplugins.iterator(); iterator.hasNext();)
// {
// PlugIn plugin = (PlugIn) iterator.next();
// plugins.put(plugin.getId(), plugin);
// }
//
// //Save dependencies for each Plugin
// for (Iterator iterator = plugindependson.keySet().iterator(); iterator.hasNext();)
// {
// String pluginid = (String) iterator.next();
// PlugIn edit = (PlugIn)plugins.get(pluginid);
// if( edit != null)
// {
// List dep = (List)plugindependson.get(edit.getId());
// if( dep != null)
// {
// for (Iterator iterator2 = dep.iterator(); iterator2.hasNext();)
// {
// String dependsid = (String) iterator2.next();
// edit.addDependsOn((PlugIn)plugins.get(dependsid));
// }
// }
// }
// }
//
// return plugins;
// }
// protected void loadPluginDefs(File inFile)
// {
// try
// {
// loadPluginDefs(new FileInputStream( inFile));
// }
// catch( IOException ex)
// {
// throw new OpenEditRuntimeException( ex);
// }
// }
//
// protected boolean loadPluginDefs( InputStream inputStream )
// {
// try
// {
// XmlBeanFactory factory = new XmlBeanFactory( new InputStreamResource( inputStream ), getBeanFactory() );
// String[] names = factory.getBeanDefinitionNames();
//
// for (int i = 0; i < names.length; i++)
// {
// BeanDefinition def = factory.getBeanDefinition(names[i]);
// String[] aliases = factory.getAliases(names[i]);
// fieldBeanFactory.registerBeanDefinition(names[i],def);
//
// for (int j = 0; j < aliases.length; j++)
// {
// fieldBeanFactory.registerAlias(names[i], aliases[j]);
//
// }
//
// }
//
//
//
//
//
// }
// catch ( Exception ex)
// {
// ex.printStackTrace();
// log.error( ex);
// return false;
//
// }
// finally
// {
// FileUtils.safeClose(inputStream);
// }
// return true;
// }
// public void overridePlugIns()
// {
// try
// {
// File overrideFile = new File( getRootDirectory(), "WEB-INF/pluginoverrides.xml" ); //TODO: Use a directory of files
// if ( overrideFile.exists() )
// {
// loadPluginDefs( overrideFile );
// }
//
// //I am not sure what this does.
// PropertyPlaceholderConfigurer configurator = new PropertyPlaceholderConfigurer();
// configurator.postProcessBeanFactory( getBeanFactory() );
//
// } catch ( Exception ex )
// {
// throw new OpenEditRuntimeException(ex);
// }
//
// }
/**
* @see com.openedit.WebServer#getPageManager()
*/
public PageManager getPageManager()
{
return (PageManager)getBeanFactory().getBean( "pageManager" );
}
/**
* @see com.openedit.WebServer#getUserManager()
*/
public UserManager getUserManager()
{
return (UserManager)getBeanFactory().getBean( "userManager" );
}
/**
* @see com.openedit.WebServer#getModuleManager()
*/
public ModuleManager getModuleManager()
{
return (ModuleManager) getBeanFactory().getBean( "moduleManager" );
}
/**
* @see com.openedit.WebServer#getOpenEditEngine()
*/
public OpenEditEngine getOpenEditEngine()
{
return (OpenEditEngine)getBeanFactory().getBean("OpenEditEngine");
}
/**
* @see com.openedit.WebServer#getRootDirectory()
*/
public File getRootDirectory()
{
if( fieldRootDirectory == null)
{
String path = System.getProperty( "oe.root.path");
if( path != null)
{
log.info("Using System default since to path set " + path);
fieldRootDirectory = new File( path ).getAbsoluteFile();
}
}
return fieldRootDirectory;
}
public void setRootDirectory(File inRoot)
{
if( inRoot != null)
{
try
{
inRoot = inRoot.getCanonicalFile();
}
catch (IOException ex)
{
throw new IllegalArgumentException("Could not convert " + inRoot,ex);
}
}
fieldRootDirectory = inRoot;
}
class DependentComparator implements Comparator
{
public int compare(Object arg0, Object arg1)
{
PlugIn plugin1 = (PlugIn)arg0;
PlugIn plugin2 = (PlugIn)arg1;
if( plugin1.dependsOn( plugin2.getId()))
{
return 1;
}
if( plugin2.dependsOn( plugin1.getId()))
{
return -1;
}
return 0;
}
}
public void reloadMounts()
{
Page mounts = getPageManager().getPage("/WEB-INF/oemounts.xml",true);
getPageManager().getRepository().getRepositories().clear();
if( mounts.exists() )
{
Element root = new XmlUtil().getXml(mounts.getInputStream(), "UTF-8");
List children = root.elements("mount");
for (Iterator iterator = children.iterator(); iterator.hasNext();)
{
Element child = (Element) iterator.next();
String repositorytype = child.attributeValue("repositorytype");
if( repositorytype == null)
{
//For legacy support. New UI uses type drop down
boolean versioncontrol = Boolean.parseBoolean(child.attributeValue("useversioncontrol"));
if (versioncontrol)
{
repositorytype = "versionRepository";
}
}
if( repositorytype == null)
{
repositorytype = "fileRepository";
}
Repository config = (Repository)getModuleManager().getBean(repositorytype);
config.setRepositoryType(repositorytype);
String path = child.attributeValue("path");
if( path == null)
{
path = "/";
}
String filter = child.attributeValue("filter");
if( filter != null)
{
if( filter.endsWith("*"))
{
//legacy support /* -> /
path = filter;
}
else
{
log.error("Invalid: " + filter + " Remove filter entries from /WEB-INF/oemounts.xml" );
config.setMatchesPostFix(filter);
}
}
path = path.replace("*", "");
if( path.length() > 1 && path.endsWith("/"))
{
path = path.substring(0, path.length()-1);
}
config.setPath(path);
config.setMatchesPostFix(child.attributeValue("matchpostfix")); //*.PDF
config.setFilterIn(child.attributeValue("filterin")); //*.PDF
if( config.getFilterIn() == null)
{
config.setFilterIn(child.attributeValue("importextensions"));
}
config.setFilterOut(child.attributeValue("filterout")); //*.old
String externalpath = child.attributeValue("externalpath");
//This is used when no external path is passed in
if( externalpath == null)
{
String rootpath = getCleanRootPath(config.getPath());
config.setExternalPath(rootpath);
}
else
{
if(externalpath.startsWith("."))
{
externalpath = PathUtilities.resolveRelativePath(externalpath, getRootDirectory().getPath() + "/WEB-INF/" );
}
config.setExternalPath(externalpath);
}
List properties = child.elements("property");
for (Iterator iterator2 = properties.iterator(); iterator2
.hasNext();)
{
Element property = (Element) iterator2.next();
String propName = property.attributeValue("name");
String value = property.getText();
config.setProperty(propName, value);
}
getPageManager().getRepository().addRepository(config);
//Might need to create the mount so we can find the virtual children
//TODO: Remove the need to create the folder
new File( getRootDirectory(), config.getPath() ).mkdirs();
}
}
else
{
//Defaults
/*
Repository repos = new XmlVersionRepository();
repos.setPath("/WEB-INF/data");
repos.setRepositoryType("versionRepository");
repos.setExternalPath(getCleanRootPath(repos.getPath()));
getPageManager().getRepository().addRepository(repos);
repos = new FileRepository();
repos.setPath("/WEB-INF");
repos.setRepositoryType("fileRepository");
repos.setExternalPath(getCleanRootPath(repos.getPath()));
getPageManager().getRepository().addRepository(repos);
repos = new XmlVersionRepository();
repos.setPath("/");
repos.setRepositoryType("fileRepository");
repos.setExternalPath(getCleanRootPath(repos.getPath()));
getPageManager().getRepository().addRepository(repos);
*/
}
getPageManager().clearCache();
getPageManager().getRepository().sort();
}
protected String getCleanRootPath(String append)
{
String root = getRootDirectory().getAbsolutePath().replace('\\', '/');
if( root.endsWith("/") )
{
root = root.substring(0, root.length()-1);
}
if( append != null && append.length() > 0)
{
root = root + append;
}
return root;
}
public void saveMounts(List mounts)
{
Element root = DocumentHelper.createDocument().addElement("mounts");
for (Iterator iterator = mounts.iterator(); iterator.hasNext();)
{
Repository existing = (Repository) iterator.next();
Element child = root.addElement("mount");
child.addAttribute("path", existing.getPath());
child.addAttribute("filterin", existing.getFilterIn());
child.addAttribute("filterout", existing.getFilterOut());
child.addAttribute("matchpostfix",existing.getMatchesPostFix()); //*.PDF
String external = existing.getExternalPath();
if( external != null )
{
String path = getCleanRootPath(existing.getPath());
if( !path.equals(external) ) //does not save any redundant data
{
child.addAttribute("externalpath", external);
}
}
child.addAttribute("repositorytype", existing.getRepositoryType());
Map properties = existing.getProperties();
if (properties != null)
{
for (Iterator iterator2 = properties.keySet().iterator(); iterator2.hasNext();)
{
String name = (String) iterator2.next();
String value = (String)properties.get(name);
Element prop = child.addElement("property");
prop.addAttribute("name", name);
prop.setText(value);
}
}
}
Page mountdata = getPageManager().getPage("/WEB-INF/oemounts.xml");
OutputStream out = getPageManager().saveToStream(mountdata);
new XmlUtil().saveXml(root, out, mountdata.getCharacterEncoding());
reloadMounts();
}
}