Index: conf/nutch-default.xml
===================================================================
--- conf/nutch-default.xml (revision 395865)
+++ conf/nutch-default.xml (working copy)
@@ -564,7 +564,7 @@
plugin.includes
- protocol-http|urlfilter-regex|parse-(text|html|js)|index-basic|query-(basic|site|url)
+ admin-(configuration|system|inject|job|listing|management|instance|scheduling|crawldb-status)|protocol-http|urlfilter-regex|parse-(text|html|js)|index-basic|query-(basic|site|url)
Regular expression naming plugin directory names to
include. Any plugin not matching this expression is excluded.
In any case you need at least include the nutch-extensionpoints plugin. By
@@ -806,4 +806,27 @@
+
+
+ admin.gui.port
+ 50060
+ Port used for the embedded webcontainer that
+ runs the administration gui.
+
+
+
+ admin.gui.realm
+ org.apache.nutch.admin.DefaultRealm
+ A class provides user lookup and authentication methods.
+ See org.apache.nutch.admin.DefaultRealm for details.
+
+
+
+
+ admin.gui.realm.password
+ admin
+ A password used by the DefaultRealm implementation.
+
+
+
Index: src/java/org/apache/nutch/admin/WebContainer.java
===================================================================
--- src/java/org/apache/nutch/admin/WebContainer.java (revision 0)
+++ src/java/org/apache/nutch/admin/WebContainer.java (revision 0)
@@ -0,0 +1,184 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+import javax.servlet.Servlet;
+
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.util.LogFormatter;
+import org.apache.nutch.plugin.Extension;
+import org.apache.nutch.plugin.PluginRuntimeException;
+import org.mortbay.http.BasicAuthenticator;
+import org.mortbay.http.SecurityConstraint;
+import org.mortbay.http.SocketListener;
+import org.mortbay.http.UserRealm;
+import org.mortbay.http.handler.SecurityHandler;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.WebApplicationContext;
+
+/**
+ * Embed {@link Servlet} container.
+ */
+public class WebContainer extends Thread {
+
+ private static final Logger LOG =
+ LogFormatter.getLogger(WebContainer.class.getName());
+
+ private Server fServer;
+
+ public WebContainer(int port, Configuration configuration) {
+ this.fServer = new Server();
+ String className = configuration.get("admin.gui.realm",
+ "org.apache.nutch.admin.DefaultRealm");
+
+ try {
+ Configurable realm = (Configurable) Class.forName(className).newInstance();
+ realm.setConf(configuration);
+ this.fServer.addRealm((UserRealm) realm);
+ } catch (Exception e) {
+ LOG.fine("unable to add realm: " + e.toString());
+ }
+
+ SocketListener listener = new SocketListener();
+ listener.setPort(port);
+ this.fServer.addListener(listener);
+ }
+
+ public void run() {
+ try {
+ this.fServer.start();
+ } catch (Exception e) {
+ LOG.fine(e.toString());
+ }
+ }
+
+ /**
+ * starts the web container.
+ * @throws IOException if container couldn't started
+ */
+ public void startContainer() throws IOException {
+ start();
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException ie) {}
+ if (this.fServer == null || !this.fServer.isStarted()) {
+ throw new IOException("Could not start web container");
+ }
+ }
+
+ /**
+ * stops the web container
+ * @throws InterruptedException
+ */
+ public void stopContainer() throws InterruptedException {
+ if (this.fServer != null && this.fServer.isStarted()) {
+ this.fServer.stop();
+ }
+ }
+
+
+ /**
+ * Deploys a set of {@link GuiComponent} extentsions as web applications.
+ *
+ * @param extensions
+ * @param theInstance
+ * @param allInstances
+ * @throws Exception
+ */
+ public void addComponentExtensions(Extension[] extensions,
+ NutchInstance theInstance, NutchInstance[] allInstances) throws Exception {
+
+ // Instantiate and configure
+ ArrayList componentList = new ArrayList();
+
+ for (int i = 0; i < extensions.length; i++) {
+ try {
+ Extension extension = extensions[i];
+ GuiComponent component =
+ (GuiComponent) extension.getExtensionInstance();
+
+ component.configure(extension, theInstance);
+ componentList.add(component);
+
+ } catch (PluginRuntimeException e) {
+ LOG.fine(e.toString());
+ }
+ }
+ GuiComponent[] components = (GuiComponent[])
+ componentList.toArray(new GuiComponent[componentList.size()]);
+
+ for (int i = 0; i < components.length; i++) {
+ GuiComponent component = components[i];
+ Extension extension = component.getExtension();
+ String jspFolder = extension.getAttribute(GuiComponent.JSP_FOLDER);
+
+ if (jspFolder == null) {
+ jspFolder = "jsp";
+ }
+
+ String jsps =
+ extension.getDescriptor().getPluginPath()
+ + File.separator
+ + jspFolder
+ + File.separator;
+
+ String contextName = "";
+ String plugName = extension.getDescriptor().getPluginId();
+
+ if (plugName.equals("admin-listing")) {
+ contextName = theInstance.getName() + "/";
+ } else {
+ contextName =
+ theInstance.getName()
+ + "/"
+ + extension.getDescriptor().getPluginId();
+ }
+
+ WebApplicationContext webContext =
+ this.fServer.addWebApplication(
+ contextName,
+ new File(jsps).getCanonicalPath()
+ );
+
+ webContext.setClassLoader(extension.getDescriptor().getClassLoader());
+ webContext.setAttribute("component", component);
+ webContext.setAttribute("components", components);
+ if (allInstances != null) {
+ webContext.setAttribute("instances", allInstances);
+ webContext.setAttribute("container", this);
+ }
+
+ SecurityHandler handler = new SecurityHandler();
+ handler.setAuthMethod("BASIC");
+ webContext.addHandler(handler);
+ webContext.setAuthenticator(new BasicAuthenticator());
+ SecurityConstraint sc = new SecurityConstraint();
+ sc.setAuthenticate(true);
+ sc.addRole(SecurityConstraint.ANY_ROLE);
+ webContext.addSecurityConstraint("/", sc);
+
+ webContext.start();
+ }
+ }
+
+}
Index: src/java/org/apache/nutch/admin/DefaultRealm.java
===================================================================
--- src/java/org/apache/nutch/admin/DefaultRealm.java (revision 0)
+++ src/java/org/apache/nutch/admin/DefaultRealm.java (revision 0)
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.mortbay.http.HashUserRealm;
+import org.mortbay.http.UserRealm;
+
+/**
+ * A simple Realm implementation that adds just one user "admin"
+ * and looks up a password from the set configuration.
+ *
+ * Nutch realms need to implement {@link Configurable} and
+ * {@link UserRealm}.
+ *
+ */
+public class DefaultRealm extends HashUserRealm implements Configurable {
+
+ private Configuration fConf;
+
+ public void setConf(Configuration conf) {
+ this.fConf = conf;
+ String password = conf.get("admin.gui.realm.password", "admin");
+ put("admin", password);
+
+ }
+
+ public Configuration getConf() {
+ return this.fConf;
+ }
+
+}
Index: src/java/org/apache/nutch/admin/AdministrationApp.java
===================================================================
--- src/java/org/apache/nutch/admin/AdministrationApp.java (revision 0)
+++ src/java/org/apache/nutch/admin/AdministrationApp.java (revision 0)
@@ -0,0 +1,201 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.mapred.JobTracker;
+import org.apache.hadoop.util.LogFormatter;
+import org.apache.nutch.plugin.Extension;
+import org.apache.nutch.plugin.ExtensionPoint;
+import org.apache.nutch.plugin.PluginRepository;
+import org.apache.nutch.util.NutchConfiguration;
+
+/**
+ * Administration Application
+ */
+public class AdministrationApp {
+
+
+ private static final Logger LOG =
+ LogFormatter.getLogger(AdministrationApp.class.getName());
+
+
+ private void startJobTracker(final Configuration defaultConf) {
+ Runnable jobTrackerStarter = new Runnable() {
+ public void run() {
+ try {
+ String jobtracker = defaultConf.get("mapred.job.tracker", "local");
+ if (!"local".equals(jobtracker)) {
+ JobTracker.startTracker(NutchConfiguration.create());
+ Thread.sleep(3000);
+ }
+ } catch (IOException e) {
+ LOG.warning(e.toString());
+ } catch (InterruptedException e) {
+ LOG.warning(e.toString());
+ }
+ }
+ };
+ Thread t = new Thread(jobTrackerStarter);
+ t.start();
+ }
+
+ /**
+ * starts a container and deploys all gui plugins
+ */
+ public WebContainer startContainer(File initialInstance, Configuration defaultConf) throws Exception {
+
+
+ int port = defaultConf.getInt("admin.gui.port", 50060);
+ WebContainer webContainer = new WebContainer(port, defaultConf);
+ webContainer.startContainer();
+
+ NutchInstance[] nutchInstances = getInstances(defaultConf, initialInstance);
+ // add all general-components
+ Extension[] generalGuiComponents =
+ getComponentExtensions(defaultConf, GuiComponent.IS_GENERAL_COMPONENT);
+ NutchInstance generalInstance =
+ new NutchInstance("general", initialInstance, defaultConf);
+ webContainer.addComponentExtensions(
+ generalGuiComponents, generalInstance, nutchInstances);
+
+ // add instance-components
+ for (int i = 0; i < nutchInstances.length; i++) {
+ NutchInstance instance = nutchInstances[i];
+ Extension[] extensions = getComponentExtensions(
+ instance.getConfiguration(), GuiComponent.IS_INSTANCE_COMPONENT);
+ webContainer.addComponentExtensions(extensions, instance, null);
+ }
+ return webContainer;
+ }
+
+ /**
+ * @param conf
+ * @param attributeName
+ * attribute value must be set to "true" in plugin.xml
+ * @return extensions implementing {@link GuiComponent}
+ * and matching the attribute filter
+ */
+ public static Extension[] getComponentExtensions(Configuration conf,
+ String attributeName) {
+ ArrayList list = new ArrayList();
+ ExtensionPoint extensionPoint =
+ PluginRepository.get(conf).getExtensionPoint(GuiComponent.X_POINT_ID);
+ if (extensionPoint == null) {
+ throw new RuntimeException("x-point "
+ + GuiComponent.X_POINT_ID
+ + " not found, check your plugin folder");
+ }
+ Extension[] extensions = extensionPoint.getExtensions();
+ for (int i = 0; i < extensions.length; i++) {
+ Extension extension = extensions[i];
+ if (extension.getAttribute(attributeName) != null
+ && extension.getAttribute(attributeName).toLowerCase().equals("true")) {
+ list.add(extension);
+ }
+ }
+ return (Extension[]) list.toArray(new Extension[list.size()]);
+
+ }
+
+ /* scans the root folder for instance folders */
+ private NutchInstance[] getInstances(Configuration defaultConf, File instancesRoot) {
+ File[] files = instancesRoot.listFiles();
+ ArrayList instancesList = new ArrayList();
+ for (int i = 0; i < files.length; i++) {
+ File folder = files[i];
+ if (folder.isDirectory() && !folder.getName().equals("conf")) {
+ try {
+ instancesList.add(loadNutchInstance(defaultConf, folder));
+ } catch (IOException e) {
+ LOG.fine("unable to load instance: " + e.toString());
+ }
+ }
+ }
+ return (NutchInstance[])
+ instancesList.toArray(new NutchInstance[instancesList.size()]);
+ }
+
+ /**
+ * creates an instance object from a instance folder
+ *
+ * @param defaultConf
+ * @param folder
+ * @return an instance representation of this folder
+ * @throws IOException
+ * in case the folder is not a valid instance folder
+ */
+ public static NutchInstance loadNutchInstance(Configuration defaultConf, File folder)
+ throws IOException {
+ File instanceConfFolder = new File(folder, "conf");
+ if (instanceConfFolder.exists() && instanceConfFolder.isDirectory()) {
+ File instanceSiteConf = new File(instanceConfFolder, "nutch-site.xml");
+ if (instanceSiteConf.exists()) {
+ Configuration instanceConf = new Configuration(defaultConf);
+ instanceConf.addFinalResource(instanceSiteConf.getAbsolutePath());
+ return new NutchInstance(folder.getName(), folder, instanceConf);
+ }
+ }
+ throw new IOException("not a valid instance folder: "
+ + folder.getAbsolutePath());
+ }
+
+ private void createFirstInstance(File file) throws IOException {
+ GuiConfigUtil.createConfiguration(file);
+ File defaultInstance = new File(file, "default");
+ GuiConfigUtil.createConfiguration(defaultInstance);
+ }
+
+
+ /**
+ * Starts the nutch administration web interface
+ *
+ * @param args
+ * @throws Exception
+ */
+ public static void main(String[] args) throws Exception {
+ String usage = "Usage: ";
+ if (args.length != 1) {
+ System.err.println(usage);
+ return;
+ }
+ AdministrationApp app = new AdministrationApp();
+ File file = new File(args[0]);
+ if (!file.exists()) {
+ app.createFirstInstance(file);
+ }
+ Configuration defaultConf =
+ GuiConfigUtil.loadNewConfiguration(file);
+ app.startJobTracker(defaultConf);
+
+ try {
+ WebContainer container = app.startContainer(file, defaultConf);
+ container.join();
+ } catch (Exception e) {
+ LOG.fine(e.getMessage());
+ System.err.println(usage);
+ }
+ }
+
+
+
+}
Index: src/java/org/apache/nutch/admin/NutchInstance.java
===================================================================
--- src/java/org/apache/nutch/admin/NutchInstance.java (revision 0)
+++ src/java/org/apache/nutch/admin/NutchInstance.java (revision 0)
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import java.io.File;
+
+import org.apache.hadoop.conf.Configuration;
+
+/**
+ * Holds instance related properties.
+ */
+public class NutchInstance {
+
+ private File fInstanceFolder;
+
+ private Configuration fInstanceConf;
+
+ private String fInstanceName;
+
+ public NutchInstance(String name, File folder, Configuration instanceConf) {
+ this.fInstanceName = name;
+ this.fInstanceFolder = folder;
+ this.fInstanceConf = instanceConf;
+ }
+
+ public String getName() {
+ return fInstanceName;
+ }
+
+ public Configuration getConfiguration() {
+ return this.fInstanceConf;
+ }
+
+ public File getInstanceFolder() {
+ return fInstanceFolder;
+ }
+
+}
Index: src/java/org/apache/nutch/admin/GuiComponent.java
===================================================================
--- src/java/org/apache/nutch/admin/GuiComponent.java (revision 0)
+++ src/java/org/apache/nutch/admin/GuiComponent.java (revision 0)
@@ -0,0 +1,108 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import java.util.Locale;
+
+import org.apache.nutch.plugin.Extension;
+
+/**
+ * An Extension point definition for functional administration interface
+ * components.
+ *
+ * The nutch functional administration interface is built form a set of plug-ins
+ * that are plugged together into a embedded web container. The extension point,
+ * the plug-ins have to implement, is named GuiComponent.
+ *
+ * To be able to manage multiple different configured deployments (e.g. intranet
+ * and home-page) we introduce the concept of so called instances. Instances use
+ * the same nutch code base and one general configuration, but can have
+ * properties that overwrite the general configured properties. Also each
+ * instance has a own data folder (local or dfs) where the databases, segments
+ * and indexes are stored.
+ *
+ * Since there is a general nutch configuration and several nutch instances we
+ * have two kind of plug-ins: general plug-ins and instance plug-ins. Instance
+ * plug-ins only have access to the instance- folder and configuration but
+ * general plug-ins have access to all instances and the general configuration.
+ *
+ * To define a plug-in as general- or instance-depending, the attributes
+ * "isGeneralComponent" or "isInstanceComponent" can be defined as true. It is
+ * also possible, that a plugin can be deployed in both contexts.
+ *
+ *
+ * The most important part of an administration interface plugin are jsp pages.
+ * Each plugin need at least one index.jsp page that is located in a folder that
+ * can be defined in the plugin.xml as attribute "jspFolder" of the extension
+ * node. Also a attribute "tabName" is required, where the value is used to show
+ * the component index page in a navigation bar.
+ *
+ * To make administration interface plugin development easier, we provide a
+ * DefaultGuiComponent that handles all functionalities and
+ * provides internationalization support. So only the
+ * DefaultGuiComponent definition in the plugin.xml, required attributes, a
+ * set of jsp pages and i18n bundles need to be defined to get a component
+ * implemented.
+ */
+public interface GuiComponent {
+
+ /** extension point id */
+ public final static String X_POINT_ID = GuiComponent.class.getName();
+
+ /**
+ * Attribute determinate if a component is general.
+ */
+ public static final String IS_GENERAL_COMPONENT = "isGeneralComponent";
+
+ /**
+ * Attribute determinate if a component is instance specific.
+ */
+ public static final String IS_INSTANCE_COMPONENT = "isInstanceComponent";
+
+ /**
+ * Attribute defines the folder inside the plugin folder contains jsp and jsp
+ * snippets.
+ */
+ public static final String JSP_FOLDER = "jspFolder";
+
+ /**
+ * Configures a component. Method is only triggered once until gui startup
+ *
+ * @param extension
+ * providing access to plugin.xml attributes
+ * @param instance
+ * providing access to configuration properties
+ */
+ public void configure(Extension extension, NutchInstance instance);
+
+ /**
+ * @param key
+ * @param locale
+ * @return localized values
+ */
+ public String getLabel(String key, Locale locale);
+
+ /**
+ * @return via configure injected extension
+ */
+ public Extension getExtension();
+
+ /**
+ * @return via configure injected instance
+ */
+ public NutchInstance getNutchInstance();
+}
Index: src/java/org/apache/nutch/admin/GuiConfigUtil.java
===================================================================
--- src/java/org/apache/nutch/admin/GuiConfigUtil.java (revision 0)
+++ src/java/org/apache/nutch/admin/GuiConfigUtil.java (revision 0)
@@ -0,0 +1,113 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.nutch.util.NutchConfiguration;
+
+/**
+ * Bundles some methods to handle configuration files
+ */
+public class GuiConfigUtil {
+
+ /**
+ * @param folder
+ * @return fresh loaded configuration
+ */
+ public static Configuration loadNewConfiguration(File folder) {
+ Configuration configuration = NutchConfiguration.create();
+ configure(configuration, folder);
+ return configuration;
+ }
+
+
+ /**
+ * Creates a configuration folder and stores nutch's configuration files
+ * in this folder.
+ *
+ * @param instanceFolder
+ * @throws IOException
+ */
+ public static void createConfiguration(File instanceFolder)
+ throws IOException {
+
+ File confFolder = new File(instanceFolder, "conf");
+ confFolder.mkdirs();
+ copyConfigurationFiles(confFolder);
+ }
+
+ private static void copyConfigurationFiles(File target)
+ throws FileNotFoundException, IOException {
+
+ InputStream in =
+ AdministrationApp.class.getResourceAsStream("/nutch-default.xml");
+ OutputStream out =
+ new FileOutputStream(new File(target,"nutch-default.xml"));
+
+ copyContent(in, out);
+
+ in = AdministrationApp.class.getResourceAsStream("/nutch-site.xml");
+ out = new FileOutputStream(new File(target, "nutch-site.xml"));
+
+ copyContent(in, out);
+ }
+
+ private static void copyContent(InputStream in, OutputStream out) throws IOException {
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ out.flush();
+ in.close();
+ out.close();
+ }
+
+ /**
+ * Push nutch-(default|site).xml from a given folder/conf
+ * into a configuration.
+ *
+ * @param configuration
+ * @param folder
+ */
+ private static void configure(Configuration configuration, File folder) {
+
+ File confFolder = new File(folder, "conf");
+
+ if (confFolder.exists()) {
+
+ File defaultConf = new File(confFolder, "nutch-default.xml");
+ if (defaultConf.exists()) {
+ configuration.addDefaultResource(new Path(defaultConf.getAbsolutePath()));
+ }
+
+ File siteConf = new File(confFolder, "nutch-site.xml");
+ if (siteConf.exists()) {
+ configuration.addFinalResource(new Path(siteConf.getAbsolutePath()));
+ }
+
+ }
+ }
+}
Index: src/java/org/apache/nutch/admin/TaskThread.java
===================================================================
--- src/java/org/apache/nutch/admin/TaskThread.java (revision 0)
+++ src/java/org/apache/nutch/admin/TaskThread.java (revision 0)
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import org.apache.hadoop.conf.Configuration;
+
+
+/**
+ * Abstract Thread used to run processes in the gui and providing process messages.
+ */
+public abstract class TaskThread extends Thread {
+
+ protected String fMessage;
+
+ protected Configuration fConfiguration;
+
+ public TaskThread(Configuration configuration) {
+ this.fConfiguration = configuration;
+ }
+
+ public String getMessage() {
+ return this.fMessage;
+ }
+
+ public abstract void run();
+}
Index: src/java/org/apache/nutch/admin/DefaultGuiComponent.java
===================================================================
--- src/java/org/apache/nutch/admin/DefaultGuiComponent.java (revision 0)
+++ src/java/org/apache/nutch/admin/DefaultGuiComponent.java (revision 0)
@@ -0,0 +1,72 @@
+/**
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.admin;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.logging.Logger;
+
+import org.apache.nutch.plugin.Extension;
+import org.apache.nutch.plugin.PluginClassLoader;
+
+/**
+ * A default implementation of the {@link GuiComponent} extension point.
+ */
+public class DefaultGuiComponent implements GuiComponent {
+
+ private static final Logger LOG =
+ Logger.getLogger(DefaultGuiComponent.class.getName());
+
+ private HashMap fResourceBundles = new HashMap();
+
+ private Extension fExtension;
+
+ private NutchInstance fNutchInstance;
+
+ public void configure(Extension extension, NutchInstance instance) {
+ this.fExtension = extension;
+ this.fNutchInstance = instance;
+ }
+
+ public String getLabel(String key, Locale locale) {
+ String value = key;
+ ResourceBundle labels = (ResourceBundle) this.fResourceBundles.get(locale);
+ if (labels == null) {
+ try {
+ PluginClassLoader classLoader =
+ this.fExtension.getDescriptor().getClassLoader();
+ String bundleName = this.fExtension.getAttribute("bundle");
+ labels = ResourceBundle.getBundle(bundleName, locale, classLoader);
+ this.fResourceBundles.put(locale, labels);
+ } catch (Exception e) {
+ LOG.warning("unable to load resource bundle: "+e.toString());
+ }
+ }
+ value = labels.getString(key);
+ return value;
+ }
+
+ public NutchInstance getNutchInstance() {
+ return this.fNutchInstance;
+ }
+
+ public Extension getExtension() {
+ return this.fExtension;
+ }
+
+}
Index: src/plugin/build.xml
===================================================================
--- src/plugin/build.xml (revision 395865)
+++ src/plugin/build.xml (working copy)
@@ -52,6 +52,15 @@
+
+
+
+
+
+
+
+
+
@@ -126,6 +135,15 @@
+
+
+
+
+
+
+
+
+
Index: src/plugin/nutch-extensionpoints/plugin.xml
===================================================================
--- src/plugin/nutch-extensionpoints/plugin.xml (revision 395865)
+++ src/plugin/nutch-extensionpoints/plugin.xml (working copy)
@@ -44,5 +44,9 @@
+
+
Index: bin/nutch
===================================================================
--- bin/nutch (revision 395865)
+++ bin/nutch (working copy)
@@ -43,6 +43,7 @@
echo " dedup remove duplicates from a set of segment indexes"
echo " plugin load a plugin and run one of its classes main()"
echo " server run a search server"
+ echo " gui run the Administration Gui"
echo " or"
echo " CLASSNAME run the class named CLASSNAME"
echo "Most commands print help when invoked w/o parameters."
@@ -149,6 +150,8 @@
CLASS=org.apache.nutch.plugin.PluginRepository
elif [ "$COMMAND" = "server" ] ; then
CLASS='org.apache.nutch.searcher.DistributedSearch$Server'
+elif [ "$COMMAND" = "gui" ] ; then
+ CLASS='org.apache.nutch.admin.AdministrationApp'
else
CLASS=$COMMAND
fi