/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nutch.webapp.tiles;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.nutch.plugin.Extension;
import org.apache.nutch.plugin.ExtensionPoint;
import org.apache.nutch.util.LogUtil;
import org.apache.nutch.webapp.common.PluginResourceLoader;
import org.apache.nutch.webapp.common.ServletContextServiceLocator;
import org.apache.nutch.webapp.common.Startable;
import org.apache.nutch.webapp.extension.UIExtensionPoint;
import org.apache.struts.tiles.ComponentDefinition;
import org.apache.struts.tiles.Controller;
import org.apache.struts.tiles.DefinitionsFactory;
import org.apache.struts.tiles.DefinitionsFactoryConfig;
import org.apache.struts.tiles.DefinitionsFactoryException;
import org.apache.struts.tiles.NoSuchDefinitionException;
import org.apache.struts.tiles.xmlDefinition.XmlDefinition;
import org.apache.struts.tiles.xmlDefinition.XmlDefinitionsSet;
import org.apache.struts.tiles.xmlDefinition.XmlParser;
import org.xml.sax.SAXException;
/**
* Tiles DefinitionsFactory that can be extended by activated plugins.
*/
public class ExtendableDefinitionsFactory implements DefinitionsFactory {
private static final long serialVersionUID = 1L;
public static final Log LOG = LogFactory
.getLog(ExtendableDefinitionsFactory.class);
DefinitionsFactoryConfig config;
protected transient XmlParser xmlParser = new XmlParser();
Map definitions;
private ServletContext servletContext;
HashMap locales = new HashMap();
public ComponentDefinition getDefinition(String name, ServletRequest request,
ServletContext servletContext) throws NoSuchDefinitionException,
DefinitionsFactoryException {
return (ComponentDefinition) definitions.get(name);
}
public void putDefinition(ComponentDefinition definition) {
LOG.info("putting definition:" + definition.getName());
definitions.put(definition.getName(), definition);
try {
definition.getOrCreateController();
} catch (Exception e) {
e.printStackTrace(LogUtil.getDebugStream(LOG));
}
}
protected XmlDefinitionsSet getDefinitions() {
LOG.debug("getDefinitions()");
XmlDefinitionsSet definitions = new XmlDefinitionsSet();
//
// core definitions
//
String configFiles = config.getDefinitionConfigFiles();
LOG.info("config files:" + configFiles);
String[] files = configFiles.split(",");
for (int i = 0; i < files.length; i++) {
LOG.info("Trying to load " + files[i]);
InputStream input = servletContext.getResourceAsStream(files[i]);
LOG.info("Stream: " + input);
if (input != null) {
parseXMLDefinitionSet(input, definitions, files[i], "nutch-core");
} else {
LOG.info("Cannot find static " + files[i]);
}
}
//
// plugged implementations can override defaults if they wish
//
ExtensionPoint point = ServletContextServiceLocator.getInstance(
servletContext).getPluginRepository().getExtensionPoint(
UIExtensionPoint.X_POINT_ID);
if (point != null) {
Extension[] extensions = point.getExtensions();
LOG.info("There are " + extensions.length
+ " extensions available for UI");
for (int i = 0; i < extensions.length; i++) {
LOG.info("Adding definitions from "
+ extensions[i].getDescriptor().getName());
Extension extension = extensions[i];
addToSet(definitions, extension);
}
} else {
LOG.info("Cannot find extension point '" + UIExtensionPoint.X_POINT_ID
+ "'");
}
try {
definitions.resolveInheritances();
} catch (NoSuchDefinitionException e) {
LOG.info("Error resolving:" + e);
}
return definitions;
}
protected void addToSet(XmlDefinitionsSet definitions, Extension extension) {
InputStream is = extension.getDescriptor().getClassLoader()
.getResourceAsStream("tiles-defs.xml");
if (is == null) {
LOG.info("Plugin " + extension.getId()
+ " did not contain tiles-defs.xml");
return;
}
parseXMLDefinitionSet(is, definitions, "Plugin " + extension.getId()
+ " : tiles-defs.xml", extension.getId());
try {
is.close();
} catch (Exception e) {
e.printStackTrace(LogUtil.getDebugStream(LOG));
}
}
protected void parseXMLDefinitionSet(InputStream input,
XmlDefinitionsSet definitions, String info, String pluginid) {
XmlDefinitionsSet newSet = new XmlDefinitionsSet();
try {
xmlParser.parse(input, newSet);
} catch (IOException e) {
LOG.info("IOException (" + e.getMessage() + ") parsing definitions "
+ info);
e.printStackTrace();
} catch (SAXException e) {
LOG.info("SAXException (" + e.getMessage() + ") parsing definitions "
+ info);
e.printStackTrace();
}
// LOG.info("Definitions:" + definitions.getDefinitions().size() + " : "
// + definitions.toString());
copySet(definitions, newSet);
}
private void copySet(XmlDefinitionsSet definitions2, XmlDefinitionsSet newSet) {
Iterator iterator = newSet.getDefinitions().keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
LOG.info("adding: " + key);
XmlDefinition value = newSet.getDefinition(key);
definitions2.putDefinition(value);
}
}
public void init(DefinitionsFactoryConfig config,
ServletContext servletContext) throws DefinitionsFactoryException {
this.config = config;
this.servletContext = servletContext;
xmlParser.setValidating(config.getParserValidate());
XmlDefinitionsSet definitions = getDefinitions();
ClassLoader current = Thread.currentThread().getContextClassLoader();
PluginResourceLoader loader = ServletContextServiceLocator.getInstance(
servletContext).getPluginResourceLoader(current);
Thread.currentThread().setContextClassLoader(loader);
initDefinitions(definitions);
Thread.currentThread().setContextClassLoader(current);
this.definitions = definitions.getDefinitions();
}
private void initDefinitions(XmlDefinitionsSet definitions) {
Iterator i = definitions.getDefinitions().keySet().iterator();
while (i.hasNext()) {
String key = (String) i.next();
if (LOG.isDebugEnabled()) {
LOG.debug("Initializing controller: " + key);
}
XmlDefinition d = definitions.getDefinition(key);
try {
Controller controller = d.getOrCreateController();
if (controller != null) {
// check if it is implementing Startable, if so execute lifecycle
// method
if (controller instanceof Startable) {
((Startable) controller).start(servletContext);
}
}
} catch (Exception e) {
e.printStackTrace(LogUtil.getDebugStream(LOG));
}
}
}
public void destroy() {
LOG.info("destroy()");
}
public void setConfig(DefinitionsFactoryConfig config,
ServletContext servletContext) throws DefinitionsFactoryException {
this.config = config;
this.servletContext = servletContext;
}
public DefinitionsFactoryConfig getConfig() {
return config;
}
}