Index: conf/nutch-default.xml
===================================================================
--- conf/nutch-default.xml	(revision 478575)
+++ conf/nutch-default.xml	(working copy)
@@ -692,7 +692,7 @@
 
 <property>
   <name>plugin.includes</name>
-  <value>protocol-http|urlfilter-regex|parse-(text|html|js)|index-basic|query-(basic|site|url)|summary-basic|scoring-opic|urlnormalizer-(pass|regex|basic)</value>
+  <value>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)|summary-basic|scoring-opic|urlnormalizer-(pass|regex|basic)</value>
   <description>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
@@ -964,4 +964,27 @@
   </description>
 </property>
 
+<!--  administration gui properties -->
+<property>
+  <name>admin.gui.port</name>
+  <value>50060</value>
+  <description>Port used for the embedded webcontainer that
+  runs the administration gui.</description>
+</property>
+
+<property>
+  <name>admin.gui.realm</name>
+  <value>org.apache.nutch.admin.DefaultRealm</value>
+  <description>A class provides user lookup and authentication methods.
+  See org.apache.nutch.admin.DefaultRealm for details.
+  </description>
+</property>
+
+<property>
+  <name>admin.gui.realm.password</name>
+  <value>admin</value>
+  <description>A password used by the DefaultRealm implementation.
+  </description>
+</property>
+
 </configuration>
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,186 @@
+/**
+ * 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 javax.servlet.Servlet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+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 Log LOG = 
+    LogFactory.getLog(WebContainer.class);
+
+  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.warn("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.warn(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<GuiComponent> componentList = new ArrayList<GuiComponent>();
+
+    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.warn(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/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 org.apache.hadoop.fs.Path;
+
+import org.apache.hadoop.conf.Configuration;
+
+/**
+ * Holds instance related properties.
+ */
+public class NutchInstance {
+
+  private Path fInstanceFolder;
+
+  private Configuration fInstanceConf;
+
+  private String fInstanceName;
+
+  public NutchInstance(String name, Path folder, Configuration instanceConf) {
+    this.fInstanceName = name;
+    this.fInstanceFolder = folder;
+    this.fInstanceConf = instanceConf;
+  }
+
+  public String getName() {
+    return fInstanceName;
+  }
+
+  public Configuration getConfiguration() {
+    return this.fInstanceConf;
+  }
+
+  public Path getInstanceFolder() {
+    return fInstanceFolder;
+  }
+
+}
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,233 @@
+/**
+ * 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.IOException;
+import java.util.ArrayList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.LocalFileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.mapred.JobTracker;
+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 Log LOG = 
+    LogFactory.getLog(AdministrationApp.class.getName());
+
+  private static FileSystem fs;
+  
+  static {
+	try {
+	  fs = new LocalFileSystem(null);
+	} catch (IOException ex) {
+	  LOG.warn(ex);
+	} 
+  }
+  
+    
+//  private Configuration conf;
+  
+  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.warn(e.toString());
+        } catch (InterruptedException e) {
+          LOG.warn(e.toString());
+        }
+      }
+    };
+    Thread t = new Thread(jobTrackerStarter);
+    t.start();
+  }
+
+//  private AdministrationApp(Configuration conf) {
+//	  setConf(conf);
+//  }
+//  
+//  private void setConf(Configuration conf) {
+//	  this.conf = conf;
+//	  try {
+//		  fs = new LocalFileSystem(conf);
+//	  }catch (Exception ex) {
+//		LOG.warn(ex);	
+//	}
+//  }
+  
+  /**
+   * starts a container and deploys all gui plugins
+   */
+  public WebContainer startContainer(Path 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<Extension> list = new ArrayList<Extension>();
+    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, Path instancesRoot) throws IOException{
+    //Path[] files = instancesRoot.listFiles();
+	
+	Path[] files = fs.listPaths(instancesRoot);
+	  
+    ArrayList<NutchInstance> instancesList = new ArrayList<NutchInstance>();
+    for (int i = 0; i < files.length; i++) {
+      Path folder = files[i];
+      if ( fs.isDirectory(folder) && !folder.getName().equals("conf")) {
+        try {
+          instancesList.add(loadNutchInstance(defaultConf, folder));
+        } catch (IOException e) {
+          LOG.warn("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, Path folder)
+      throws IOException {
+    Path instanceConfFolder = new Path(folder, "conf");
+    if (fs.exists(instanceConfFolder) && fs.isDirectory(instanceConfFolder)) {
+      Path instanceSiteConf = new Path(instanceConfFolder, "nutch-site.xml");
+      if ( fs.exists(instanceSiteConf)) {
+        Configuration instanceConf = new Configuration(defaultConf);
+        //instanceConf.addFinalResource( instanceSiteConf.getAbsolutePath());
+        instanceConf.addFinalResource(instanceSiteConf);
+        return new NutchInstance(folder.getName(), folder, instanceConf);
+      }
+    }
+    throw new IOException("not a valid instance folder: "
+        + folder);
+  }
+
+  private void createFirstInstance(Path file) throws IOException {
+    GuiConfigUtil.createConfiguration(file);
+    Path defaultInstance = new Path(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: <instancesFolder>";
+    if (args.length != 1) {
+      System.err.println(usage);
+      return;
+    }
+    AdministrationApp app = new AdministrationApp();
+    Path file = new Path(args[0]);
+    if (!fs.exists(file)) {
+      app.createFirstInstance(file);
+    }
+    Configuration defaultConf = 
+      GuiConfigUtil.loadNewConfiguration(file);
+    app.startJobTracker(defaultConf);
+    
+    try {
+      WebContainer container = app.startContainer(file, defaultConf);
+      container.join();
+    } catch (Exception e) {
+      LOG.warn(e.getMessage());
+      System.err.println(usage);
+    }
+  }
+
+
+
+}
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
+ * <code>DefaultGuiComponent</code> that handles all functionalities and
+ * provides internationalization support. So only the
+ * <code>DefaultGuiComponent</code> 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,126 @@
+/**
+ * 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.LocalFileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.nutch.util.NutchConfiguration;
+
+/**
+ * Bundles some methods to handle configuration files
+ */
+public class GuiConfigUtil {
+
+  private static LocalFileSystem fs;	
+	
+  static {
+	try {
+	  fs = new LocalFileSystem(null);
+	} catch (IOException ex) {
+	  ex.printStackTrace();
+	}  
+  }
+	
+  /**
+   * Creates a new configuration, then writes the new configuration to the 
+   * path
+   * @param folder the path of the new configuration
+   * @return fresh loaded configuration
+   */
+  public static Configuration loadNewConfiguration(Path folder) throws IOException{
+    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(Path instanceFolder)
+      throws IOException {
+
+    Path confFolder = new Path(instanceFolder, "conf");
+    fs.mkdirs(confFolder);
+    copyConfigurationFiles(confFolder);
+  }
+
+  private static void copyConfigurationFiles(Path target)
+      throws FileNotFoundException, IOException {
+    
+    InputStream in = 
+      AdministrationApp.class.getResourceAsStream("/nutch-default.xml");
+    OutputStream out =
+      new FileOutputStream(new File(fs.pathToFile(target),"nutch-default.xml"));
+    
+    copyContent(in, out);
+    
+    in = AdministrationApp.class.getResourceAsStream("/nutch-site.xml");
+    out = new FileOutputStream(new File(fs.pathToFile(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, Path folder) throws IOException{
+  
+    Path confFolder = new Path(folder, "conf");
+
+    if (fs.exists(confFolder)) {
+
+      Path defaultConf = new Path(confFolder, "nutch-default.xml");
+      if (fs.exists(defaultConf)) {
+        //configuration.addDefaultResource(new Path(defaultConf.getAbsolutePath()));
+    	  configuration.addDefaultResource(new Path(defaultConf.toString()));
+      }
+
+      Path siteConf = new Path(confFolder, "nutch-site.xml");
+      if (fs.exists(siteConf)) {
+        configuration.addFinalResource(new Path(siteConf.toString()));
+      }
+
+    }
+  }
+}
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 478575)
+++ src/plugin/build.xml	(working copy)
@@ -61,6 +61,17 @@
      <ant dir="urlnormalizer-basic" target="deploy"/>
      <ant dir="urlnormalizer-pass" target="deploy"/>
      <ant dir="urlnormalizer-regex" target="deploy"/>
+
+     <ant dir="admin-instance" target="deploy"/>
+     <ant dir="admin-listing" target="deploy"/>
+     <ant dir="admin-configuration" target="deploy"/>
+     <ant dir="admin-inject" target="deploy"/>
+     <ant dir="admin-management" target="deploy"/>
+     <ant dir="admin-system" target="deploy"/>
+     <ant dir="admin-job" target="deploy"/>
+     <ant dir="admin-scheduling" target="deploy"/>
+     <ant dir="admin-crawldb-status" target="deploy"/>
+
   </target>
 
   <!-- ====================================================== -->
@@ -150,5 +161,15 @@
     <ant dir="urlnormalizer-basic" target="clean"/>
     <ant dir="urlnormalizer-pass" target="clean"/>
     <ant dir="urlnormalizer-regex" target="clean"/>
+
+    <ant dir="admin-instance" target="clean"/>
+    <ant dir="admin-listing" target="clean"/>
+    <ant dir="admin-configuration" target="clean"/>
+    <ant dir="admin-inject" target="clean"/>
+    <ant dir="admin-management" target="clean"/>
+    <ant dir="admin-system" target="clean"/>
+    <ant dir="admin-job" target="clean"/>
+    <ant dir="admin-scheduling" target="clean"/>
+    <ant dir="admin-crawldb-status" target="clean"/>
   </target>
 </project>
Index: src/plugin/nutch-extensionpoints/plugin.xml
===================================================================
--- src/plugin/nutch-extensionpoints/plugin.xml	(revision 478575)
+++ src/plugin/nutch-extensionpoints/plugin.xml	(working copy)
@@ -48,6 +48,10 @@
 <extension-point
       id="org.apache.nutch.analysis.NutchAnalyzer"
       name="Nutch Analysis"/>
+      
+<extension-point
+      id="org.apache.nutch.admin.GuiComponent"
+      name="Nutch Administration Gui Component"/>      
 
 <extension-point
       id="org.apache.nutch.searcher.Summarizer"
Index: bin/nutch
===================================================================
--- bin/nutch	(revision 478575)
+++ bin/nutch	(working copy)
@@ -51,6 +51,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."
@@ -184,6 +185,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
