Index: build.xml
===================================================================
--- build.xml (revision 1618258)
+++ build.xml (working copy)
@@ -102,6 +102,11 @@
+
+
+
+
+
Index: default.properties
===================================================================
--- default.properties (revision 1618258)
+++ default.properties (working copy)
@@ -61,7 +61,7 @@
runtime.deploy=${runtime.dir}/deploy
runtime.local=${runtime.dir}/local
-ivy.version=2.2.0
+ivy.version=2.3.0
ivy.dir=${basedir}/ivy
ivy.file=${ivy.dir}/ivy.xml
ivy.jar=${ivy.dir}/ivy-${ivy.version}.jar
Index: ivy/ivy.xml
===================================================================
--- ivy/ivy.xml (revision 1618258)
+++ ivy/ivy.xml (working copy)
@@ -69,7 +69,12 @@
-
+
+
+
+
@@ -88,13 +93,10 @@
+
+
+
-
-
-
-
@@ -126,7 +128,24 @@
-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: src/bin/nutch
===================================================================
--- src/bin/nutch (revision 1618258)
+++ src/bin/nutch (working copy)
@@ -74,6 +74,7 @@
echo " indexchecker check the indexing filters for a given url"
echo " plugin load a plugin and run one of its classes main()"
echo " nutchserver run a (local) Nutch server on a user defined port"
+ echo " webapp run a local Nutch web application"
echo " junit runs the given JUnit test"
echo " or"
echo " CLASSNAME run the class named CLASSNAME"
@@ -234,6 +235,8 @@
CLASS=org.apache.nutch.indexer.IndexingFiltersChecker
elif [ "$COMMAND" = "plugin" ] ; then
CLASS=org.apache.nutch.plugin.PluginRepository
+elif [ "$COMMAND" = "webapp" ] ; then
+CLASS=org.apache.nutch.webui.NutchUiServer
elif [ "$COMMAND" = "nutchserver" ] ; then
CLASS=org.apache.nutch.api.NutchServer
elif [ "$COMMAND" = "junit" ] ; then
Index: src/java/org/apache/nutch/api/NutchServer.java
===================================================================
--- src/java/org/apache/nutch/api/NutchServer.java (revision 1618258)
+++ src/java/org/apache/nutch/api/NutchServer.java (working copy)
@@ -42,6 +42,7 @@
import org.apache.nutch.api.resources.ConfigResource;
import org.apache.nutch.api.resources.DbResource;
import org.apache.nutch.api.resources.JobResource;
+import org.apache.nutch.api.resources.SeedResource;
import org.restlet.Component;
import org.restlet.Context;
import org.restlet.data.Protocol;
@@ -118,6 +119,7 @@
resources.add(AdminResource.class);
resources.add(ConfigResource.class);
resources.add(DbResource.class);
+ resources.add(SeedResource.class);
return resources;
}
Index: src/java/org/apache/nutch/api/impl/NutchServerPoolExecutor.java
===================================================================
--- src/java/org/apache/nutch/api/impl/NutchServerPoolExecutor.java (revision 1618258)
+++ src/java/org/apache/nutch/api/impl/NutchServerPoolExecutor.java (working copy)
@@ -100,4 +100,13 @@
}
return jobsInfo;
}
+
+ public JobInfo getInfo(String jobId) {
+ for (JobInfo jobInfo : getAllJobs()) {
+ if(StringUtils.equals(jobId, jobInfo.getId())){
+ return jobInfo;
+ }
+ }
+ return null;
+ }
}
Index: src/java/org/apache/nutch/api/impl/RAMJobManager.java
===================================================================
--- src/java/org/apache/nutch/api/impl/RAMJobManager.java (revision 1618258)
+++ src/java/org/apache/nutch/api/impl/RAMJobManager.java (working copy)
@@ -52,7 +52,7 @@
@Override
public JobInfo get(String crawlId, String jobId) {
- return executor.findWorker(jobId).getInfo();
+ return executor.getInfo(jobId);
}
@Override
Index: src/java/org/apache/nutch/webui/NutchUiApplication.java
===================================================================
--- src/java/org/apache/nutch/webui/NutchUiApplication.java (revision 0)
+++ src/java/org/apache/nutch/webui/NutchUiApplication.java (working copy)
@@ -0,0 +1,72 @@
+/**
+ * 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.webui;
+
+import org.apache.nutch.webui.pages.DashboardPage;
+import org.apache.nutch.webui.pages.assets.NutchUiCssReference;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import de.agilecoders.wicket.core.Bootstrap;
+import de.agilecoders.wicket.core.markup.html.themes.bootstrap.BootstrapCssReference;
+import de.agilecoders.wicket.core.settings.BootstrapSettings;
+import de.agilecoders.wicket.core.settings.SingleThemeProvider;
+import de.agilecoders.wicket.core.settings.Theme;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeCssReference;
+
+@Component
+public class NutchUiApplication extends WebApplication implements ApplicationContextAware {
+ private static final String THEME_NAME = "bootstrap";
+ private ApplicationContext context;
+
+ /**
+ * @see org.apache.wicket.Application#getHomePage()
+ */
+ @Override
+ public Class extends WebPage> getHomePage() {
+ return DashboardPage.class;
+ }
+
+ /**
+ * @see org.apache.wicket.Application#init()
+ */
+ @Override
+ public void init() {
+ super.init();
+ BootstrapSettings settings = new BootstrapSettings();
+ Bootstrap.install(this, settings);
+ configureTheme(settings);
+
+ getComponentInstantiationListeners().add(new SpringComponentInjector(this, context));
+ }
+
+ private void configureTheme(BootstrapSettings settings) {
+ Theme theme = new Theme(THEME_NAME, BootstrapCssReference.instance(),
+ FontAwesomeCssReference.instance(), NutchUiCssReference.instance());
+ settings.setThemeProvider(new SingleThemeProvider(theme));
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.context = applicationContext;
+ }
+}
Index: src/java/org/apache/nutch/webui/NutchUiApplication.properties
===================================================================
--- src/java/org/apache/nutch/webui/NutchUiApplication.properties (revision 0)
+++ src/java/org/apache/nutch/webui/NutchUiApplication.properties (working copy)
@@ -0,0 +1,63 @@
+#############################################################################
+#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.
+#############################################################################
+
+navbar.menu.dashboard = Dashboard
+navbar.menu.statistics = Statistics
+navbar.menu.instances = Instances
+navbar.menu.settings = Settings
+navbar.menu.crawls = Crawls
+navbar.menu.scheduling = Scheduling
+navbar.menu.search = Search
+navbar.menu.url = URLs upload
+navbar.menu.seedLists = Seed lists
+
+page.header.seedList = Seed list
+
+navbar.userMenu.settings = Settings
+navbar.userMenu.logout = Log out
+
+menu.settings=Settings
+menu.instances=Instances
+
+connected=Connected
+disconnected=Disconnected
+
+##ENUMS
+ConnectionStatus.CONNECTING=Connecting
+ConnectionStatus.CONNECTED=Connected
+ConnectionStatus.DISCONNECTED=Disconnected
+
+CrawlStatus.NEW=New
+CrawlStatus.ERROR=Error
+CrawlStatus.CRAWLING=Crawling
+CrawlStatus.FINISHED=Finished
+
+instances=Instances
+instances.header.name=Instance name
+instances.header.hostname=Hostname
+instances.header.status=Status
+instances.header.username=Username
+instances.label.name=Instance name
+instances.label.hostname=Hostname
+instances.label.port=Port
+instances.label.username=Username
+instances.label.password=Password
+instances.buttons.addInstance=Add instance
+
+settings=Settings
+settings.header.name = Name
+settings.header.value = Value
\ No newline at end of file
Index: src/java/org/apache/nutch/webui/NutchUiServer.java
===================================================================
--- src/java/org/apache/nutch/webui/NutchUiServer.java (revision 0)
+++ src/java/org/apache/nutch/webui/NutchUiServer.java (working copy)
@@ -0,0 +1,64 @@
+/**
+ * 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.webui;
+
+import org.apache.wicket.protocol.http.WicketFilter;
+import org.apache.wicket.spring.SpringWebApplicationFactory;
+import org.mortbay.jetty.Handler;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.DefaultServlet;
+import org.mortbay.jetty.servlet.FilterHolder;
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.request.RequestContextListener;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+public class NutchUiServer {
+ private static final String APP_FACTORY_NAME = SpringWebApplicationFactory.class.getName();
+ private static final String CONFIG_LOCATION = "org.apache.nutch.webui";
+
+ public static void main(String[] args) throws Exception {
+ startServer();
+ }
+
+ private static void startServer() throws Exception, InterruptedException {
+ Server server = new Server(8080);
+ Context context = new Context(server, "/", Context.SESSIONS);
+ context.addServlet(DefaultServlet.class, "/*");
+
+ context.addEventListener(new ContextLoaderListener(getContext()));
+ context.addEventListener(new RequestContextListener());
+
+ WicketFilter filter = new WicketFilter();
+ filter.setFilterPath("/");
+ FilterHolder holder = new FilterHolder(filter);
+ holder.setInitParameter("applicationFactoryClassName", APP_FACTORY_NAME);
+ context.addFilter(holder, "/*", Handler.DEFAULT);
+
+ server.setHandler(context);
+ server.start();
+ server.join();
+ }
+
+ private static WebApplicationContext getContext() {
+ AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+ context.setConfigLocation(CONFIG_LOCATION);
+ return context;
+ }
+
+}
Index: src/java/org/apache/nutch/webui/client/NutchClient.java
===================================================================
--- src/java/org/apache/nutch/webui/client/NutchClient.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/NutchClient.java (working copy)
@@ -0,0 +1,49 @@
+/**
+ * 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.webui.client;
+
+import java.util.Map;
+
+import org.apache.nutch.webui.client.model.ConnectionStatus;
+import org.apache.nutch.webui.client.model.JobConfig;
+import org.apache.nutch.webui.client.model.JobInfo;
+import org.apache.nutch.webui.client.model.NutchStatus;
+import org.apache.nutch.webui.model.NutchInstance;
+import org.apache.nutch.webui.model.SeedList;
+
+public interface NutchClient {
+
+ public NutchInstance getNutchInstance();
+
+ public NutchStatus getNutchStatus();
+
+ public ConnectionStatus getConnectionStatus();
+
+ public String executeJob(JobConfig jobConfig);
+
+ public JobInfo getJobInfo(String jobId);
+
+ public Map getNutchConfig(String config);
+
+ /**
+ * Create seed list and return seed directory location
+ *
+ * @param seedList
+ * @return
+ */
+ public String createSeed(SeedList seedList);
+}
Index: src/java/org/apache/nutch/webui/client/NutchClientFactory.java
===================================================================
--- src/java/org/apache/nutch/webui/client/NutchClientFactory.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/NutchClientFactory.java (working copy)
@@ -0,0 +1,51 @@
+/**
+ * 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.webui.client;
+
+import java.util.concurrent.ExecutionException;
+
+import org.apache.nutch.webui.client.impl.NutchClientImpl;
+import org.apache.nutch.webui.model.NutchInstance;
+import org.springframework.stereotype.Component;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+@Component
+public class NutchClientFactory {
+ private LoadingCache cache;
+
+ public NutchClientFactory() {
+ cache = CacheBuilder.newBuilder().build(new NutchClientCacheLoader());
+ }
+
+ public NutchClient getClient(NutchInstance instance) {
+ try {
+ return cache.get(instance);
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static class NutchClientCacheLoader extends CacheLoader {
+ @Override
+ public NutchClient load(NutchInstance key) throws Exception {
+ return new NutchClientImpl(key);
+ }
+ }
+}
Index: src/java/org/apache/nutch/webui/client/impl/CrawlingCycle.java
===================================================================
--- src/java/org/apache/nutch/webui/client/impl/CrawlingCycle.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/impl/CrawlingCycle.java (working copy)
@@ -0,0 +1,81 @@
+/**
+ * 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.webui.client.impl;
+
+import java.util.List;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.nutch.webui.client.model.Crawl;
+import org.apache.nutch.webui.client.model.JobInfo;
+import org.apache.nutch.webui.client.model.JobInfo.State;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+/**
+ * This class implements crawl cycle as in crawl script
+ *
+ * @author feodor
+ *
+ */
+public class CrawlingCycle {
+ private Logger log = LoggerFactory.getLogger(CrawlingCycle.class);
+
+ private CrawlingCycleListener listener;
+ private RemoteCommandExecutor executor;
+ private Crawl crawl;
+
+ private List remoteCommands;
+ private List executedCommands = Lists.newArrayList();
+
+ public CrawlingCycle(CrawlingCycleListener listener, RemoteCommandExecutor executor, Crawl crawl,
+ List commands) {
+ this.listener = listener;
+ this.executor = executor;
+ this.crawl = crawl;
+ this.remoteCommands = commands;
+ }
+
+ public synchronized void executeCrawlCycle() {
+ listener.crawlingStarted(crawl);
+
+ for (RemoteCommand command : remoteCommands) {
+ JobInfo jobInfo = executor.executeRemoteJob(command);
+ command.setJobInfo(jobInfo);
+
+ log.info("Executed remote command data: {}", command);
+
+ if (jobInfo.getState() == State.FAILED) {
+ listener.onCrawlError(crawl, jobInfo.getMsg());
+ return;
+ }
+
+ executedCommands.add(command);
+ listener.commandExecuted(crawl, command, calculateProgress());
+ }
+ listener.crawlingFinished(crawl);
+ }
+
+ private int calculateProgress() {
+ if (CollectionUtils.isEmpty(remoteCommands)) {
+ return 0;
+ }
+ return (int) ((float) executedCommands.size() / (float) remoteCommands.size() * 100);
+ }
+
+}
Index: src/java/org/apache/nutch/webui/client/impl/CrawlingCycleListener.java
===================================================================
--- src/java/org/apache/nutch/webui/client/impl/CrawlingCycleListener.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/impl/CrawlingCycleListener.java (working copy)
@@ -0,0 +1,31 @@
+/**
+ * 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.webui.client.impl;
+
+import org.apache.nutch.webui.client.model.Crawl;
+
+public interface CrawlingCycleListener {
+
+ void crawlingStarted(Crawl crawl);
+
+ void onCrawlError(Crawl crawl, String msg);
+
+ void commandExecuted(Crawl crawl, RemoteCommand command, int progress);
+
+ void crawlingFinished(Crawl crawl);
+
+}
Index: src/java/org/apache/nutch/webui/client/impl/NutchClientImpl.java
===================================================================
--- src/java/org/apache/nutch/webui/client/impl/NutchClientImpl.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/impl/NutchClientImpl.java (working copy)
@@ -0,0 +1,92 @@
+/**
+ * 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.webui.client.impl;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.util.Map;
+
+import org.apache.nutch.webui.client.NutchClient;
+import org.apache.nutch.webui.client.model.ConnectionStatus;
+import org.apache.nutch.webui.client.model.JobConfig;
+import org.apache.nutch.webui.client.model.JobInfo;
+import org.apache.nutch.webui.client.model.NutchStatus;
+import org.apache.nutch.webui.model.NutchInstance;
+import org.apache.nutch.webui.model.SeedList;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.api.json.JSONConfiguration;
+
+public class NutchClientImpl implements NutchClient {
+ private Client client;
+ private WebResource nutchResource;
+ private NutchInstance instance;
+
+ public NutchClientImpl(NutchInstance instance) {
+ this.instance = instance;
+ createClient();
+ }
+
+ public void createClient() {
+ ClientConfig clientConfig = new DefaultClientConfig();
+ clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, true);
+ this.client = Client.create(clientConfig);
+ this.nutchResource = client.resource(instance.getUrl());
+ }
+
+ @Override
+ public NutchStatus getNutchStatus() {
+ return nutchResource.path("/admin").type(APPLICATION_JSON).get(NutchStatus.class);
+ }
+
+ @Override
+ public ConnectionStatus getConnectionStatus() {
+
+ getNutchStatus();
+ return ConnectionStatus.CONNECTED;
+ // TODO implement disconnected status
+ }
+
+ @Override
+ public String executeJob(JobConfig jobConfig) {
+ return nutchResource.path("/job/create").type(APPLICATION_JSON).post(String.class, jobConfig);
+ }
+
+ @Override
+ public JobInfo getJobInfo(String jobId) {
+ return nutchResource.path("/job/" + jobId).type(APPLICATION_JSON).get(JobInfo.class);
+ }
+
+ @Override
+ public NutchInstance getNutchInstance() {
+ return instance;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Map getNutchConfig(String config) {
+ return nutchResource.path("/config/" + config).type(APPLICATION_JSON).get(Map.class);
+ }
+
+ @Override
+ public String createSeed(SeedList seedList) {
+ return nutchResource.path("/seed/create").type(APPLICATION_JSON).post(String.class, seedList);
+ }
+}
Index: src/java/org/apache/nutch/webui/client/impl/RemoteCommand.java
===================================================================
--- src/java/org/apache/nutch/webui/client/impl/RemoteCommand.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/impl/RemoteCommand.java (working copy)
@@ -0,0 +1,75 @@
+/**
+ * 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.webui.client.impl;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nutch.webui.client.model.JobConfig;
+import org.apache.nutch.webui.client.model.JobInfo;
+import org.joda.time.Duration;
+
+public class RemoteCommand implements Serializable {
+ private JobConfig jobConfig;
+ private JobInfo jobInfo = new JobInfo();
+ private Duration timeout;
+
+ /**
+ * Use {@link RemoteCommandBuilder} instead
+ */
+ @SuppressWarnings("unused")
+ private RemoteCommand() {
+ }
+
+ public RemoteCommand(JobConfig jobConfig) {
+ this.jobConfig = jobConfig;
+ }
+
+ public JobConfig getJobConfig() {
+ return jobConfig;
+ }
+
+ public void setJobConfig(JobConfig jobConfig) {
+ this.jobConfig = jobConfig;
+ }
+
+ public JobInfo getJobInfo() {
+ return jobInfo;
+ }
+
+ public void setJobInfo(JobInfo jobInfo) {
+ this.jobInfo = jobInfo;
+ }
+
+ public Duration getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(Duration timeout) {
+ this.timeout = timeout;
+ }
+
+ @Override
+ public String toString() {
+ String statusInfo = StringUtils.EMPTY;
+ if (jobInfo != null) {
+ statusInfo = MessageFormat.format("{0}", jobInfo.getState());
+ }
+ return MessageFormat.format("{0} status: {1}", jobConfig.getType(), statusInfo);
+ }
+}
Index: src/java/org/apache/nutch/webui/client/impl/RemoteCommandBuilder.java
===================================================================
--- src/java/org/apache/nutch/webui/client/impl/RemoteCommandBuilder.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/impl/RemoteCommandBuilder.java (working copy)
@@ -0,0 +1,62 @@
+/**
+ * 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.webui.client.impl;
+
+import org.apache.nutch.webui.client.model.JobConfig;
+import org.apache.nutch.webui.client.model.JobInfo.JobType;
+import org.joda.time.Duration;
+
+public class RemoteCommandBuilder {
+ private JobConfig jobConfig = new JobConfig();
+ private Duration timeout = Duration.standardSeconds(10);
+
+ private RemoteCommandBuilder() {
+ }
+
+ public static RemoteCommandBuilder instance(JobType jobType) {
+ return new RemoteCommandBuilder().withJobType(jobType);
+ }
+
+ public RemoteCommandBuilder withJobType(JobType jobType) {
+ jobConfig.setType(jobType);
+ return this;
+ }
+
+ public RemoteCommandBuilder withConfigId(String configId) {
+ jobConfig.setConfId(configId);
+ return this;
+ }
+ public RemoteCommandBuilder withCrawlId(String crawlId) {
+ jobConfig.setCrawlId(crawlId);
+ return this;
+ }
+ public RemoteCommandBuilder withArgument(String key, String value) {
+ jobConfig.setArgument(key, value);
+ return this;
+ }
+
+ public RemoteCommandBuilder withTimeout(Duration timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ public RemoteCommand build() {
+ RemoteCommand remoteCommand = new RemoteCommand(jobConfig);
+ remoteCommand.setTimeout(timeout);
+ return remoteCommand;
+ }
+}
Index: src/java/org/apache/nutch/webui/client/impl/RemoteCommandExecutor.java
===================================================================
--- src/java/org/apache/nutch/webui/client/impl/RemoteCommandExecutor.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/impl/RemoteCommandExecutor.java (working copy)
@@ -0,0 +1,109 @@
+/**
+ * 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.webui.client.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.nutch.webui.client.NutchClient;
+import org.apache.nutch.webui.client.model.JobInfo;
+import org.apache.nutch.webui.client.model.JobInfo.State;
+import org.joda.time.DateTimeConstants;
+import org.joda.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class executes remote job and waits for success/failure result
+ *
+ * @author feodor
+ *
+ */
+public class RemoteCommandExecutor {
+ private Logger log = LoggerFactory.getLogger(RemoteCommandExecutor.class);
+
+ private static final int DEFAULT_TIMEOUT_SEC = 60;
+ private Duration requestDelay = new Duration(500);
+
+ private NutchClient client;
+ private ExecutorService executor;
+
+ public RemoteCommandExecutor(NutchClient client) {
+ this.client = client;
+ this.executor = Executors.newSingleThreadExecutor();
+ }
+
+ public JobInfo executeRemoteJob(RemoteCommand command) {
+ try {
+ String jobId = client.executeJob(command.getJobConfig());
+ Future chekerFuture = executor.submit(new JobStateChecker(jobId));
+ return chekerFuture.get(getTimeout(command), TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ log.error("Remote command failed", e);
+ JobInfo jobInfo = new JobInfo();
+ jobInfo.setState(State.FAILED);
+ jobInfo.setMsg(ExceptionUtils.getStackTrace(e));
+ return jobInfo;
+ }
+ }
+
+ private long getTimeout(RemoteCommand command) {
+ if (command.getTimeout() == null) {
+ return DEFAULT_TIMEOUT_SEC * DateTimeConstants.MILLIS_PER_SECOND;
+ }
+ return command.getTimeout().getMillis();
+ }
+
+ public void setRequestDelay(Duration requestDelay) {
+ this.requestDelay = requestDelay;
+ }
+
+ public class JobStateChecker implements Callable {
+
+ private String jobId;
+
+ public JobStateChecker(String jobId) {
+ this.jobId = jobId;
+ }
+
+ @Override
+ public JobInfo call() throws Exception {
+ while (!Thread.interrupted()) {
+ JobInfo jobInfo = client.getJobInfo(jobId);
+ checkState(jobInfo != null, "Cannot get job info!");
+
+ State state = jobInfo.getState();
+ checkState(state != null, "Unknown job state!");
+
+ if (state == State.RUNNING || state == State.ANY || state == State.IDLE) {
+ Thread.sleep(requestDelay.getMillis());
+ continue;
+ }
+
+ return jobInfo;
+ }
+ return null;
+ }
+
+ }
+}
Index: src/java/org/apache/nutch/webui/client/impl/RemoteCommandsBatchFactory.java
===================================================================
--- src/java/org/apache/nutch/webui/client/impl/RemoteCommandsBatchFactory.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/impl/RemoteCommandsBatchFactory.java (working copy)
@@ -0,0 +1,95 @@
+/**
+ * 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.webui.client.impl;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.nutch.webui.client.model.Crawl;
+import org.apache.nutch.webui.client.model.JobInfo.JobType;
+import org.joda.time.Duration;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import com.google.common.collect.Lists;
+
+@Component
+@Scope(BeanDefinition.SCOPE_PROTOTYPE)
+public class RemoteCommandsBatchFactory {
+
+ private List remoteCommands;
+ private Crawl crawl;
+
+ private String batchId;
+
+ public List createCommands(Crawl crawl) {
+ this.crawl = crawl;
+ this.remoteCommands = Lists.newArrayList();
+
+ remoteCommands.add(inject());
+ for (int i = 0; i < crawl.getNumberOfRounds(); i++) {
+ remoteCommands.addAll(createBatchCommands());
+ }
+ return remoteCommands;
+ }
+
+ private List createBatchCommands() {
+ this.batchId = UUID.randomUUID().toString();
+ List batchCommands = Lists.newArrayList();
+
+ batchCommands.add(createGenerateCommand());
+ batchCommands.add(createFetchCommand());
+ batchCommands.add(createParseCommand());
+ batchCommands.add(createUpdateDbCommand());
+ batchCommands.add(createIndexCommand());
+
+ return batchCommands;
+ }
+
+ private RemoteCommand inject() {
+ RemoteCommandBuilder builder = RemoteCommandBuilder.instance(JobType.INJECT)
+ .withCrawlId(crawl.getCrawlId()).withArgument("seedDir", crawl.getSeedDirectory());
+ return builder.build();
+ }
+
+ private RemoteCommand createGenerateCommand() {
+ return createBuilder(JobType.GENERATE).build();
+ }
+
+ private RemoteCommand createFetchCommand() {
+ return createBuilder(JobType.FETCH).withTimeout(Duration.standardSeconds(50)).build();
+ }
+
+ private RemoteCommand createParseCommand() {
+ return createBuilder(JobType.PARSE).build();
+ }
+
+ private RemoteCommand createIndexCommand() {
+ return createBuilder(JobType.INDEX).build();
+ }
+
+ private RemoteCommand createUpdateDbCommand() {
+ return createBuilder(JobType.UPDATEDB).build();
+ }
+
+ private RemoteCommandBuilder createBuilder(JobType jobType) {
+ return RemoteCommandBuilder.instance(jobType).withCrawlId(crawl.getCrawlId())
+ .withArgument("batch", batchId);
+ }
+
+}
Index: src/java/org/apache/nutch/webui/client/model/ConnectionStatus.java
===================================================================
--- src/java/org/apache/nutch/webui/client/model/ConnectionStatus.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/model/ConnectionStatus.java (working copy)
@@ -0,0 +1,21 @@
+/**
+ * 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.webui.client.model;
+
+public enum ConnectionStatus {
+ CONNECTING, CONNECTED, DISCONNECTED;
+}
\ No newline at end of file
Index: src/java/org/apache/nutch/webui/client/model/Crawl.java
===================================================================
--- src/java/org/apache/nutch/webui/client/model/Crawl.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/model/Crawl.java (working copy)
@@ -0,0 +1,126 @@
+/**
+ * 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.webui.client.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.apache.nutch.webui.model.SeedList;
+
+import com.j256.ormlite.field.DatabaseField;
+
+@Entity
+public class Crawl implements Serializable {
+ public enum CrawlStatus {
+ NEW, CRAWLING, FINISHED, ERROR
+ }
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column
+ private String crawlId;
+
+ @Column
+ private String crawlName;
+
+ @Column
+ private CrawlStatus status = CrawlStatus.NEW;
+
+ @Column
+ private Integer numberOfRounds = 1;
+
+ @Column
+ @DatabaseField(foreign = true, foreignAutoRefresh = true)
+ private SeedList seedList;
+
+ @Column
+ private String seedDirectory;
+
+ @Column
+ private int progress;
+
+ public Integer getNumberOfRounds() {
+ return numberOfRounds;
+ }
+
+ public void setNumberOfRounds(Integer numberOfRounds) {
+ this.numberOfRounds = numberOfRounds;
+ }
+
+ public String getCrawlId() {
+ return crawlId;
+ }
+
+ public void setCrawlId(String crawlId) {
+ this.crawlId = crawlId;
+ }
+
+ public CrawlStatus getStatus() {
+ return status;
+ }
+
+ public void setStatus(CrawlStatus status) {
+ this.status = status;
+ }
+
+ public String getCrawlName() {
+ return crawlName;
+ }
+
+ public void setCrawlName(String crawlName) {
+ this.crawlName = crawlName;
+ }
+
+ public SeedList getSeedList() {
+ return seedList;
+ }
+
+ public void setSeedList(SeedList seedList) {
+ this.seedList = seedList;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getSeedDirectory() {
+ return seedDirectory;
+ }
+
+ public void setSeedDirectory(String seedDirectory) {
+ this.seedDirectory = seedDirectory;
+ }
+
+ public int getProgress() {
+ return progress;
+ }
+
+ public void setProgress(int progress) {
+ this.progress = progress;
+ }
+
+}
Index: src/java/org/apache/nutch/webui/client/model/JobConfig.java
===================================================================
--- src/java/org/apache/nutch/webui/client/model/JobConfig.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/model/JobConfig.java (working copy)
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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.webui.client.model;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.nutch.webui.client.model.JobInfo.JobType;
+
+import com.google.common.collect.Maps;
+
+public class JobConfig implements Serializable {
+ private String crawlId;
+ private JobType type;
+ private String confId = "default";
+ private String jobClassName;
+ private Map args = Maps.newHashMap();
+
+ public void setArgument(String key, String value) {
+ args.put(key, value);
+ }
+
+ public String getCrawlId() {
+ return crawlId;
+ }
+
+ public void setCrawlId(String crawlId) {
+ this.crawlId = crawlId;
+ }
+
+ public JobType getType() {
+ return type;
+ }
+
+ public void setType(JobType type) {
+ this.type = type;
+ }
+
+ public String getConfId() {
+ return confId;
+ }
+
+ public void setConfId(String confId) {
+ this.confId = confId;
+ }
+
+ public Map getArgs() {
+ return Collections.unmodifiableMap(args);
+ }
+
+ public void setArgs(Map args) {
+ this.args = args;
+ }
+
+ public String getJobClassName() {
+ return jobClassName;
+ }
+
+ public void setJobClassName(String jobClass) {
+ this.jobClassName = jobClass;
+ }
+}
Index: src/java/org/apache/nutch/webui/client/model/JobInfo.java
===================================================================
--- src/java/org/apache/nutch/webui/client/model/JobInfo.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/model/JobInfo.java (working copy)
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * 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.webui.client.model;
+
+import java.io.Serializable;
+import java.util.Map;
+
+public class JobInfo implements Serializable {
+ public static enum JobType {
+ INJECT, GENERATE, FETCH, PARSE, UPDATEDB, INDEX, READDB, CLASS
+ };
+
+ public static enum State {
+ IDLE, RUNNING, FINISHED, FAILED, KILLED, STOPPING, KILLING, ANY
+ };
+
+ private String id;
+ private String type;
+ private String confId;
+ private Map args;
+ private Map result;
+ private State state;
+ private String msg;
+ private String crawlId;
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ public Map getResult() {
+ return result;
+ }
+
+ public void setResult(Map result) {
+ this.result = result;
+ }
+
+ public Map getArgs() {
+ return args;
+ }
+
+ public void setArgs(Map args) {
+ this.args = args;
+ }
+
+ public String getConfId() {
+ return confId;
+ }
+
+ public void setConfId(String confId) {
+ this.confId = confId;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getCrawlId() {
+ return crawlId;
+ }
+
+ public void setCrawlId(String crawlId) {
+ this.crawlId = crawlId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+}
Index: src/java/org/apache/nutch/webui/client/model/NutchStatus.java
===================================================================
--- src/java/org/apache/nutch/webui/client/model/NutchStatus.java (revision 0)
+++ src/java/org/apache/nutch/webui/client/model/NutchStatus.java (working copy)
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.webui.client.model;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+
+public class NutchStatus implements Serializable {
+
+ private Date startDate;
+ private Set configuration;
+ private Collection jobs;
+ private Collection runningJobs;
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ public Set getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(Set configuration) {
+ this.configuration = configuration;
+ }
+
+ public Collection getJobs() {
+ return jobs;
+ }
+
+ public void setJobs(Collection jobs) {
+ this.jobs = jobs;
+ }
+
+ public Collection getRunningJobs() {
+ return runningJobs;
+ }
+
+ public void setRunningJobs(Collection runningJobs) {
+ this.runningJobs = runningJobs;
+ }
+}
Index: src/java/org/apache/nutch/webui/config/CustomDaoFactory.java
===================================================================
--- src/java/org/apache/nutch/webui/config/CustomDaoFactory.java (revision 0)
+++ src/java/org/apache/nutch/webui/config/CustomDaoFactory.java (working copy)
@@ -0,0 +1,57 @@
+/**
+ * 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.webui.config;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.spring.DaoFactory;
+import com.j256.ormlite.support.ConnectionSource;
+
+public class CustomDaoFactory {
+ private ConnectionSource connectionSource;
+ private List> registredDaos = Collections.synchronizedList(new ArrayList>());
+
+ public CustomDaoFactory(ConnectionSource connectionSource) {
+ this.connectionSource = connectionSource;
+ }
+
+ public Dao createDao(Class clazz) {
+ try {
+ Dao dao = DaoFactory.createDao(connectionSource, clazz);
+ register(dao);
+ return dao;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void register(Dao dao) {
+ synchronized (registredDaos) {
+ registredDaos.add(dao);
+ }
+ }
+
+ public List> getCreatedDaos() {
+ synchronized (registredDaos) {
+ return Collections.unmodifiableList(registredDaos);
+ }
+ }
+}
Index: src/java/org/apache/nutch/webui/config/CustomTableCreator.java
===================================================================
--- src/java/org/apache/nutch/webui/config/CustomTableCreator.java (revision 0)
+++ src/java/org/apache/nutch/webui/config/CustomTableCreator.java (working copy)
@@ -0,0 +1,81 @@
+/**
+ * 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.webui.config;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import com.j256.ormlite.dao.BaseDaoImpl;
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.support.ConnectionSource;
+import com.j256.ormlite.table.DatabaseTableConfig;
+import com.j256.ormlite.table.TableUtils;
+
+public class CustomTableCreator {
+
+ private ConnectionSource connectionSource;
+ private List> configuredDaos;
+
+ public CustomTableCreator(ConnectionSource connectionSource, List> configuredDaos) {
+ this.connectionSource = connectionSource;
+ this.configuredDaos = configuredDaos;
+ initialize();
+ }
+
+ private void initialize() {
+ if (configuredDaos == null) {
+ throw new IllegalStateException("configuredDaos was not set in " + getClass().getSimpleName());
+ }
+
+ for (Dao, ?> dao : configuredDaos) {
+ createTableForDao(dao);
+ }
+ }
+
+ private void createTableForDao(Dao, ?> dao) {
+ DatabaseTableConfig> tableConfig = getTableConfig(dao);
+ createTableIfNotExists(tableConfig);
+ }
+
+ private DatabaseTableConfig> getTableConfig(Dao, ?> dao) {
+ Class> clazz = dao.getDataClass();
+ DatabaseTableConfig> tableConfig = null;
+ if (dao instanceof BaseDaoImpl) {
+ tableConfig = ((BaseDaoImpl, ?>) dao).getTableConfig();
+ }
+ if (tableConfig == null) {
+ return getConfigFromClass(clazz);
+ }
+ return tableConfig;
+ }
+
+ private DatabaseTableConfig> getConfigFromClass(Class> clazz) {
+ try {
+ return DatabaseTableConfig.fromClass(connectionSource, clazz);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void createTableIfNotExists(DatabaseTableConfig> tableConfig) {
+ try {
+ TableUtils.createTableIfNotExists(connectionSource, tableConfig);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
Index: src/java/org/apache/nutch/webui/config/NutchGuiConfiguration.java
===================================================================
--- src/java/org/apache/nutch/webui/config/NutchGuiConfiguration.java (revision 0)
+++ src/java/org/apache/nutch/webui/config/NutchGuiConfiguration.java (working copy)
@@ -0,0 +1,33 @@
+/**
+ * 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.webui.config;
+
+import java.util.List;
+
+import org.apache.nutch.webui.model.NutchInstance;
+
+public class NutchGuiConfiguration {
+ private List instances;
+
+ public List getInstances() {
+ return instances;
+ }
+
+ public void setInstances(List instances) {
+ this.instances = instances;
+ }
+}
Index: src/java/org/apache/nutch/webui/config/SpringConfiguration.java
===================================================================
--- src/java/org/apache/nutch/webui/config/SpringConfiguration.java (revision 0)
+++ src/java/org/apache/nutch/webui/config/SpringConfiguration.java (working copy)
@@ -0,0 +1,90 @@
+/**
+ * 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.webui.config;
+
+import java.sql.SQLException;
+import java.util.concurrent.Executor;
+
+import org.apache.nutch.webui.client.model.Crawl;
+import org.apache.nutch.webui.model.NutchInstance;
+import org.apache.nutch.webui.model.SeedList;
+import org.apache.nutch.webui.model.SeedUrl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.db.H2DatabaseType;
+import com.j256.ormlite.jdbc.JdbcConnectionSource;
+
+@Configuration
+@EnableAsync
+public class SpringConfiguration implements AsyncConfigurer {
+
+ @Override
+ public Executor getAsyncExecutor() {
+ // TODO move magic numbers to properties file
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(7);
+ executor.setMaxPoolSize(42);
+ executor.setQueueCapacity(11);
+ executor.setThreadNamePrefix("SpringExecutor-");
+ executor.initialize();
+ return executor;
+ }
+
+ @Bean
+ public JdbcConnectionSource getConnectionSource() throws SQLException {
+ JdbcConnectionSource source = new JdbcConnectionSource("jdbc:h2:~/.nutch/config",
+ new H2DatabaseType());
+ source.initialize();
+ return source;
+ }
+
+ @Bean
+ public CustomDaoFactory getDaoFactory() throws SQLException {
+ return new CustomDaoFactory(getConnectionSource());
+ }
+
+ @Bean
+ public Dao createNutchDao() throws SQLException {
+ return getDaoFactory().createDao(NutchInstance.class);
+ }
+
+ @Bean
+ public Dao createSeedListDao() throws SQLException {
+ return getDaoFactory().createDao(SeedList.class);
+ }
+
+ @Bean
+ public Dao createSeedUrlDao() throws SQLException {
+ return getDaoFactory().createDao(SeedUrl.class);
+ }
+
+ @Bean
+ public Dao createCrawlDao() throws SQLException {
+ return getDaoFactory().createDao(Crawl.class);
+ }
+
+ @Bean
+ public CustomTableCreator createTableCreator() throws SQLException {
+ return new CustomTableCreator(getConnectionSource(), getDaoFactory().getCreatedDaos());
+ }
+
+}
Index: src/java/org/apache/nutch/webui/model/NutchConfig.java
===================================================================
--- src/java/org/apache/nutch/webui/model/NutchConfig.java (revision 0)
+++ src/java/org/apache/nutch/webui/model/NutchConfig.java (working copy)
@@ -0,0 +1,19 @@
+package org.apache.nutch.webui.model;
+
+public class NutchConfig {
+ private String name = "name";
+ private String value;
+
+ public void setName (String name){
+ this.name = name;
+ }
+ public String getName(){
+ return this.name;
+ }
+ public String getValue() {
+ return value;
+ }
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
Index: src/java/org/apache/nutch/webui/model/NutchInstance.java
===================================================================
--- src/java/org/apache/nutch/webui/model/NutchInstance.java (revision 0)
+++ src/java/org/apache/nutch/webui/model/NutchInstance.java (working copy)
@@ -0,0 +1,118 @@
+/**
+ * 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.webui.model;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.apache.nutch.webui.client.model.ConnectionStatus;
+
+@Entity
+public class NutchInstance implements Serializable {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column
+ private String name = "localhost";
+
+ @Column
+ private String host = "localhost";
+
+ @Column
+ private Integer port = 8081;
+
+ @Column
+ private String username;
+
+ @Column
+ private String password;
+
+ private ConnectionStatus connectionStatus;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(Integer port) {
+ this.port = port;
+ }
+
+ public ConnectionStatus getConnectionStatus() {
+ return connectionStatus;
+ }
+
+ public void setConnectionStatus(ConnectionStatus connectionStatus) {
+ this.connectionStatus = connectionStatus;
+ }
+
+ public URI getUrl() {
+ try {
+ return new URI("http", null, host, port, null, null, null);
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException("Cannot parse url parameters", e);
+ }
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+}
Index: src/java/org/apache/nutch/webui/model/SeedList.java
===================================================================
--- src/java/org/apache/nutch/webui/model/SeedList.java (revision 0)
+++ src/java/org/apache/nutch/webui/model/SeedList.java (working copy)
@@ -0,0 +1,104 @@
+/**
+ * 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.webui.model;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.codehaus.jackson.annotate.JsonIgnore;
+
+import com.j256.ormlite.field.ForeignCollectionField;
+
+@Entity
+public class SeedList implements Serializable {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column
+ private String name;
+
+ @OneToMany
+ @ForeignCollectionField(eager = true)
+ private Collection seedUrls;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ @JsonIgnore
+ public int getSeedUrlsCount() {
+ if (CollectionUtils.isEmpty(seedUrls)) {
+ return 0;
+ }
+ return seedUrls.size();
+ }
+
+ public Collection getSeedUrls() {
+ return seedUrls;
+ }
+
+ public void setSeedUrls(Collection seedUrls) {
+ this.seedUrls = seedUrls;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SeedList other = (SeedList) obj;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ return true;
+ }
+
+}
Index: src/java/org/apache/nutch/webui/model/SeedUrl.java
===================================================================
--- src/java/org/apache/nutch/webui/model/SeedUrl.java (revision 0)
+++ src/java/org/apache/nutch/webui/model/SeedUrl.java (working copy)
@@ -0,0 +1,95 @@
+/**
+ * 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.webui.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.codehaus.jackson.annotate.JsonIgnore;
+
+import com.j256.ormlite.field.DatabaseField;
+
+@Entity
+public class SeedUrl implements Serializable {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column
+ @DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
+ @JsonIgnore
+ private SeedList seedList;
+
+ @Column
+ private String url;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ @JsonIgnore
+ public SeedList getSeedList() {
+ return seedList;
+ }
+
+ @JsonIgnore
+ public void setSeedList(SeedList seedList) {
+ this.seedList = seedList;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SeedUrl other = (SeedUrl) obj;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ return true;
+ }
+}
Index: src/java/org/apache/nutch/webui/pages/AbstractBasePage.html
===================================================================
--- src/java/org/apache/nutch/webui/pages/AbstractBasePage.html (revision 0)
+++ src/java/org/apache/nutch/webui/pages/AbstractBasePage.html (working copy)
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+Apache Nutch
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: src/java/org/apache/nutch/webui/pages/AbstractBasePage.java
===================================================================
--- src/java/org/apache/nutch/webui/pages/AbstractBasePage.java (revision 0)
+++ src/java/org/apache/nutch/webui/pages/AbstractBasePage.java (working copy)
@@ -0,0 +1,167 @@
+/**
+ * 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.webui.pages;
+
+import static de.agilecoders.wicket.core.markup.html.bootstrap.navbar.Navbar.ComponentPosition.LEFT;
+import static de.agilecoders.wicket.core.markup.html.bootstrap.navbar.NavbarComponents.transform;
+
+import java.util.List;
+
+import org.apache.nutch.webui.model.NutchInstance;
+import org.apache.nutch.webui.pages.crawls.CrawlsPage;
+import org.apache.nutch.webui.pages.instances.InstancesPage;
+import org.apache.nutch.webui.pages.menu.VerticalMenu;
+import org.apache.nutch.webui.pages.seed.SeedListsPage;
+import org.apache.nutch.webui.pages.settings.SettingsPage;
+import org.apache.nutch.webui.service.NutchInstanceService;
+import org.apache.nutch.webui.service.NutchService;
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.markup.html.GenericWebPage;
+import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.DropDownButton;
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.MenuBookmarkablePageLink;
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.MenuDivider;
+import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
+import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;
+import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.Navbar.ComponentPosition;
+import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.Navbar.Position;
+import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.NavbarButton;
+import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.NavbarComponents;
+import de.agilecoders.wicket.core.markup.html.bootstrap.navbar.NavbarDropDownButton;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconType;
+
+public abstract class AbstractBasePage extends GenericWebPage {
+ @SpringBean
+ private NutchService service;
+
+ @SpringBean
+ private NutchInstanceService instanceService;
+
+ private VerticalMenu navbar;
+
+ protected IModel currentInstance = new InstanceModel();
+
+ public AbstractBasePage() {
+ navbar = new VerticalMenu("navigation");
+ navbar.brandName(Model.of("Apache Nutch GUI"));
+ navbar.setInverted(true);
+ navbar.setPosition(Position.TOP);
+ add(navbar);
+
+ addMenuItem(DashboardPage.class, "navbar.menu.dashboard", FontAwesomeIconType.dashboard);
+ addMenuItem(StatisticsPage.class, "navbar.menu.statistics", FontAwesomeIconType.bar_chart_o);
+ addMenuItem(InstancesPage.class, "navbar.menu.instances", FontAwesomeIconType.gears);
+ addMenuItem(SettingsPage.class, "navbar.menu.settings", FontAwesomeIconType.wrench);
+ addMenuItem(CrawlsPage.class, "navbar.menu.crawls", FontAwesomeIconType.refresh);
+ addMenuItem(SchedulingPage.class, "navbar.menu.scheduling", FontAwesomeIconType.clock_o);
+ addMenuItem(SearchPage.class, "navbar.menu.search", FontAwesomeIconType.search);
+ addMenuItem(SeedListsPage.class, "navbar.menu.seedLists", FontAwesomeIconType.file);
+
+ navbar.addComponents(transform(ComponentPosition.RIGHT, addInstancesMenuMenu()));
+ navbar.addComponents(transform(ComponentPosition.RIGHT, addUserMenu()));
+
+ add(new NotificationPanel("globalNotificationPanel"));
+
+ if (currentInstance.getObject() == null && !(this instanceof InstancesPage)) {
+ getSession().error("No running instances found!");
+ setResponsePage(InstancesPage.class);
+ }
+ }
+
+ protected Component addUserMenu() {
+ DropDownButton userMenu = new NavbarDropDownButton(Model.of("Username")) {
+ @Override
+ protected List newSubMenuButtons(final String buttonMarkupId) {
+ List subMenu = Lists.newArrayList();
+ subMenu.add(new MenuBookmarkablePageLink(UserSettingsPage.class, new ResourceModel(
+ "navbar.userMenu.settings")).setIconType(FontAwesomeIconType.gear));
+ subMenu.add(new MenuDivider());
+ subMenu.add(new MenuBookmarkablePageLink(LogOutPage.class, new ResourceModel(
+ "navbar.userMenu.logout")).setIconType(FontAwesomeIconType.power_off));
+ return subMenu;
+ }
+ }.setIconType(FontAwesomeIconType.user);
+ return userMenu;
+ }
+
+ protected Component addInstancesMenuMenu() {
+ IModel instanceName = PropertyModel.of(currentInstance, "name");
+ DropDownButton instancesMenu = new NavbarDropDownButton(instanceName) {
+
+ @Override
+ protected List newSubMenuButtons(String buttonMarkupId) {
+ List instances = instanceService.getInstances();
+ List subMenu = Lists.newArrayList();
+ for (NutchInstance instance : instances) {
+ subMenu.add(new Link(buttonMarkupId, Model.of(instance)) {
+ @Override
+ public void onClick() {
+ currentInstance.setObject(getModelObject());
+ setResponsePage(DashboardPage.class);
+ }
+ }.setBody(Model.of(instance.getName())));
+ }
+ return subMenu;
+ }
+ }.setIconType(FontAwesomeIconType.gears);
+
+ return instancesMenu;
+ }
+
+ private
+
+
+
Index: src/java/org/apache/nutch/webui/pages/DashboardPage.java
===================================================================
--- src/java/org/apache/nutch/webui/pages/DashboardPage.java (revision 0)
+++ src/java/org/apache/nutch/webui/pages/DashboardPage.java (working copy)
@@ -0,0 +1,56 @@
+/**
+ * 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.webui.pages;
+
+import org.apache.nutch.webui.client.model.NutchStatus;
+import org.apache.nutch.webui.model.NutchInstance;
+import org.apache.nutch.webui.pages.instances.InstancesPage;
+import org.apache.nutch.webui.service.NutchService;
+import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.apache.wicket.util.time.Duration;
+
+public class DashboardPage extends AbstractBasePage