You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@falcon.apache.org by ve...@apache.org on 2013/11/14 00:58:14 UTC
[1/2] git commit: FALCON-190 Entity list REST API should allow the
client to query different fields. Contributed by Haohui Mai
Updated Branches:
refs/heads/master bf63dbf19 -> 9e376c20e
FALCON-190 Entity list REST API should allow the client to query different fields. Contributed by Haohui Mai
Project: http://git-wip-us.apache.org/repos/asf/incubator-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-falcon/commit/7de95ad7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-falcon/tree/7de95ad7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-falcon/diff/7de95ad7
Branch: refs/heads/master
Commit: 7de95ad78a0a8b3b2a7e856ba488d2b57a749aed
Parents: bf63dbf
Author: Venkatesh Seetharam <ve...@apache.org>
Authored: Wed Nov 13 15:52:23 2013 -0800
Committer: Venkatesh Seetharam <ve...@apache.org>
Committed: Wed Nov 13 15:52:23 2013 -0800
----------------------------------------------------------------------
CHANGES.txt | 3 ++
.../falcon/resource/AbstractEntityManager.java | 26 +++++++---
.../proxy/SchedulableEntityManagerProxy.java | 5 +-
.../resource/SchedulableEntityManager.java | 5 +-
.../falcon/resource/EntityManagerJerseyIT.java | 53 ++++++++++++++------
5 files changed, 64 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/7de95ad7/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 8dfb5b9..226e0f0 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -78,6 +78,9 @@ Trunk (Unreleased)
IMPROVEMENTS
+ FALCON-190 Entity list REST API should allow the client to
+ query different fields (Haohui Mai via Venkatesh Seetharam)
+
FALCON-188 hadoop-2 profile is not carried through to
oozie package (Haohui Mai via Venkatesh Seetharam)
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/7de95ad7/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java b/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
index c899407..7ec6cd1 100644
--- a/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
+++ b/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
@@ -436,9 +436,17 @@ public abstract class AbstractEntityManager {
* Returns the list of entities registered of a given type.
*
* @param type entity type
+ * @param fieldStr fields that the query is interested in, separated by comma
+ *
+ * @param type entity type
* @return String
*/
- public EntityList getDependencies(String type) {
+ public EntityList getEntityList(String type, String fieldStr) {
+ HashSet<String> fields = new HashSet<String>(Arrays.asList(fieldStr.split(",")));
+
+ // Currently only the status of the entity is supported
+ boolean requireStatus = fields.contains("status");
+
try {
EntityType entityType = EntityType.valueOf(type.toUpperCase());
final String entityTypeString = type.toLowerCase();
@@ -456,14 +464,16 @@ public abstract class AbstractEntityManager {
EntityList.EntityElement elem = new EntityList.EntityElement();
elem.name = e.getName();
elem.type = entityTypeString;
- String statusString;
- try {
- EntityStatus status = getStatus(e, entityType);
- statusString = status.name();
- } catch (FalconException e1) {
- statusString = "UNKNOWN";
+ if (requireStatus) {
+ String statusString;
+ try {
+ EntityStatus status = getStatus(e, entityType);
+ statusString = status.name();
+ } catch (FalconException e1) {
+ statusString = "UNKNOWN";
+ }
+ elem.status = statusString;
}
- elem.status = statusString;
elements[i++] = elem;
}
return new EntityList(elements);
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/7de95ad7/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java b/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
index 0b6b34a..8ba2a97 100644
--- a/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
+++ b/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
@@ -283,8 +283,9 @@ public class SchedulableEntityManagerProxy extends AbstractSchedulableEntityMana
@Path("list/{type}")
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_JSON})
@Override
- public EntityList getDependencies(@PathParam("type") String type) {
- return super.getDependencies(type);
+ public EntityList getEntityList(@PathParam("type") String type,
+ @DefaultValue("") @QueryParam("fields") String fields) {
+ return super.getEntityList(type, fields);
}
@GET
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/7de95ad7/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java b/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
index b17dcc8..3c9078d 100644
--- a/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
+++ b/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java
@@ -58,8 +58,9 @@ public class SchedulableEntityManager extends AbstractSchedulableEntityManager {
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_JSON})
@Monitored(event = "dependencies")
@Override
- public EntityList getDependencies(@Dimension("type") @PathParam("type") String type) {
- return super.getDependencies(type);
+ public EntityList getEntityList(@Dimension("type") @PathParam("type") String type,
+ @DefaultValue("") @QueryParam("fields") String fields) {
+ return super.getEntityList(type, fields);
}
@GET
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/7de95ad7/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java b/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
index 767ff4b..cb2fcbb 100644
--- a/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
+++ b/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java
@@ -79,7 +79,7 @@ public class EntityManagerJerseyIT {
public void testLibExtensions() throws Exception {
TestContext context = newContext();
Map<String, String> overlay = context.getUniqueOverlay();
- ClientResponse response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ ClientResponse response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
FileSystem fs = context.getCluster().getFileSystem();
assertLibs(fs, new Path("/project/falcon/working/libext/FEED/retention"));
@@ -296,7 +296,7 @@ public class EntityManagerJerseyIT {
ClientResponse response;
Map<String, String> overlay = context.getUniqueOverlay();
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
response = context.submitToFalcon(TestContext.FEED_TEMPLATE1, overlay, EntityType.FEED);
@@ -319,10 +319,10 @@ public class EntityManagerJerseyIT {
ClientResponse response;
Map<String, String> overlay = context.getUniqueOverlay();
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
}
@@ -382,7 +382,7 @@ public class EntityManagerJerseyIT {
Map<String, String> overlay = context.getUniqueOverlay();
InputStream stream = context.getServletInputStream(
- context.overlayParametersOverTemplate(context.CLUSTER_TEMPLATE, overlay));
+ context.overlayParametersOverTemplate(TestContext.CLUSTER_TEMPLATE, overlay));
clientRepsonse = context.service.path("api/entities/validate/cluster")
.accept(MediaType.TEXT_XML).type(MediaType.TEXT_XML)
@@ -397,7 +397,7 @@ public class EntityManagerJerseyIT {
ClientResponse clientRepsonse;
Map<String, String> overlay = context.getUniqueOverlay();
- clientRepsonse = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay,
+ clientRepsonse = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay,
EntityType.CLUSTER);
context.assertSuccessful(clientRepsonse);
@@ -435,7 +435,7 @@ public class EntityManagerJerseyIT {
ClientResponse response;
Map<String, String> overlay = context.getUniqueOverlay();
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
response = context.submitToFalcon(TestContext.FEED_TEMPLATE1, overlay, EntityType.FEED);
@@ -454,7 +454,7 @@ public class EntityManagerJerseyIT {
ClientResponse response;
Map<String, String> overlay = context.getUniqueOverlay();
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
response = context.submitToFalcon(TestContext.FEED_TEMPLATE1, overlay, EntityType.FEED);
@@ -509,7 +509,7 @@ public class EntityManagerJerseyIT {
ClientResponse response;
Map<String, String> overlay = context.getUniqueOverlay();
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
response = context.submitToFalcon(TestContext.FEED_TEMPLATE1, overlay, EntityType.FEED);
@@ -580,7 +580,7 @@ public class EntityManagerJerseyIT {
ClientResponse response;
Map<String, String> overlay = context.getUniqueOverlay();
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
response = context.submitToFalcon(TestContext.FEED_TEMPLATE1, overlay, EntityType.FEED);
@@ -599,7 +599,7 @@ public class EntityManagerJerseyIT {
ClientResponse response;
Map<String, String> overlay = context.getUniqueOverlay();
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
response = context.submitToFalcon(TestContext.FEED_TEMPLATE1, overlay, EntityType.FEED);
@@ -650,7 +650,7 @@ public class EntityManagerJerseyIT {
}
@Test
- public void testGetDependencies() throws Exception {
+ public void testGetEntityList() throws Exception {
TestContext context = newContext();
ClientResponse response;
response = context.service
@@ -660,14 +660,35 @@ public class EntityManagerJerseyIT {
Assert.assertEquals(response.getStatus(), 200);
Map<String, String> overlay = context.getUniqueOverlay();
-
- response = context.submitToFalcon(context.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
+ overlay.put("cluster", "WTF-" + overlay.get("cluster"));
+ response = context.submitToFalcon(TestContext.CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER);
context.assertSuccessful(response);
response = context.service
.path("api/entities/list/cluster/")
- .header("Remote-User", TestContext.REMOTE_USER).type(MediaType.TEXT_XML)
- .accept(MediaType.TEXT_XML).get(ClientResponse.class);
+ .header("Remote-User", TestContext.REMOTE_USER)
+ .type(MediaType.TEXT_XML)
+ .accept(MediaType.TEXT_XML)
+ .get(ClientResponse.class);
Assert.assertEquals(response.getStatus(), 200);
+ EntityList result = response.getEntity(EntityList.class);
+ Assert.assertNotNull(result);
+ for (EntityList.EntityElement entityElement : result.getElements()) {
+ Assert.assertNull(entityElement.status); // status is null
+ }
+
+ response = context.service
+ .path("api/entities/list/cluster/")
+ .queryParam("fields", "status")
+ .header("Remote-User", TestContext.REMOTE_USER)
+ .type(MediaType.APPLICATION_JSON)
+ .accept(MediaType.APPLICATION_JSON)
+ .get(ClientResponse.class);
+ Assert.assertEquals(response.getStatus(), 200);
+ result = response.getEntity(EntityList.class);
+ Assert.assertNotNull(result);
+ for (EntityList.EntityElement entityElement : result.getElements()) {
+ Assert.assertNotNull(entityElement.status); // status is null
+ }
}
}
[2/2] git commit: Dashboard related changes: FALCON-164 Provide
Falcon Web UI. Contributed by Haohui Mai FALCON-178 Implement client-side
pagination. Contributed by Haohui Mai FALCON-175 Visualize dependency
information. Contributed by Haohui Mai FALCON-
Posted by ve...@apache.org.
Dashboard related changes:
FALCON-164 Provide Falcon Web UI. Contributed by Haohui Mai
FALCON-178 Implement client-side pagination. Contributed by Haohui Mai
FALCON-175 Visualize dependency information. Contributed by Haohui Mai
FALCON-193 Update the documentation for dashboard. Contributed by Haohui Mai
Project: http://git-wip-us.apache.org/repos/asf/incubator-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-falcon/commit/9e376c20
Tree: http://git-wip-us.apache.org/repos/asf/incubator-falcon/tree/9e376c20
Diff: http://git-wip-us.apache.org/repos/asf/incubator-falcon/diff/9e376c20
Branch: refs/heads/master
Commit: 9e376c20e3d9fa449c0ea10310d9fb396cf62223
Parents: 7de95ad
Author: Venkatesh Seetharam <ve...@apache.org>
Authored: Wed Nov 13 15:57:48 2013 -0800
Committer: Venkatesh Seetharam <ve...@apache.org>
Committed: Wed Nov 13 15:57:48 2013 -0800
----------------------------------------------------------------------
CHANGES.txt | 14 +-
docs/src/site/twiki/InstallationSteps.twiki | 4 +
docs/src/site/twiki/restapi/EntityList.twiki | 27 +-
docs/src/site/twiki/restapi/ResourceList.twiki | 2 +-
html5-ui/css/falcon.css | 138 +++++++++++
html5-ui/entity.html | 110 ++++++++
html5-ui/img/falcon-114.png | Bin 0 -> 17181 bytes
html5-ui/img/falcon-144.png | Bin 0 -> 23857 bytes
html5-ui/img/falcon-57.png | Bin 0 -> 8036 bytes
html5-ui/img/falcon-64.png | Bin 0 -> 8020 bytes
html5-ui/img/falcon-72.png | Bin 0 -> 9276 bytes
html5-ui/img/falcon.png | Bin 0 -> 12349 bytes
html5-ui/img/falcon.xcf | Bin 0 -> 42007 bytes
html5-ui/img/favicon.png | Bin 0 -> 8020 bytes
html5-ui/index.html | 74 ++++++
html5-ui/js/falcon-entity.js | 262 ++++++++++++++++++++
html5-ui/js/falcon-index.js | 107 ++++++++
html5-ui/js/falcon.js | 139 +++++++++++
pom.xml | 1 +
prism/pom.xml | 7 +-
webapp/pom.xml | 15 +-
21 files changed, 890 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 226e0f0..182e504 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -5,7 +5,19 @@ Trunk (Unreleased)
INCOMPATIBLE CHANGES
NEW FEATURES
-
+
+ FALCON-193 Update the documentation to reflect the current
+ work of dashboard (Haohui Mai via Venkatesh Seetharam)
+
+ FALCON-175 Visualize dependency information
+ (Haohui Mai via Venkatesh Seetharam)
+
+ FALCON-178 Implement client-side pagination
+ (Haohui Mai via Venkatesh Seetharam)
+
+ FALCON-164 Provide Falcon Web UI
+ (Haohui Mai via Venkatesh Seetharam)
+
FALCON-85 Hive (HCatalog) integration. (Venkatesh Seetharam
via Srikanth Sundarrajan)
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/docs/src/site/twiki/InstallationSteps.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/InstallationSteps.twiki b/docs/src/site/twiki/InstallationSteps.twiki
index 223242b..e396747 100644
--- a/docs/src/site/twiki/InstallationSteps.twiki
+++ b/docs/src/site/twiki/InstallationSteps.twiki
@@ -202,6 +202,10 @@ bin/falcon help
(for more details about falcon cli usage)
</verbatim>
+*Dashboard*
+
+Once falcon / prism is started, you can view the status of falcon entities using the Web-based dashboard. The web UI works in both distributed and embedded mode. You can open your browser at the corresponding port to use the web UI.
+
*Stopping Falcon Server*
<verbatim>
bin/falcon-stop
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/docs/src/site/twiki/restapi/EntityList.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityList.twiki b/docs/src/site/twiki/restapi/EntityList.twiki
index 45416ad..bca84b0 100644
--- a/docs/src/site/twiki/restapi/EntityList.twiki
+++ b/docs/src/site/twiki/restapi/EntityList.twiki
@@ -1,4 +1,4 @@
----++ GET /api/entities/list/:entity-type
+---++ GET /api/entities/list/:entity-type?fields=:fields
* <a href="#Description">Description</a>
* <a href="#Parameters">Parameters</a>
* <a href="#Results">Results</a>
@@ -9,6 +9,8 @@ Get list of the entities.
---++ Parameters
* :entity-type can be cluster, feed or process.
+ * :fields (optional) additional fields that the client are interested in, separated by commas.
+ Currently falcon only support status as a valid field.
---++ Results
List of the entities.
@@ -35,3 +37,26 @@ Remote-User: rgautam
}
</verbatim>
+---+++ Rest Call
+<verbatim>
+GET http://localhost:15000/api/entities/list/feed?fields=status
+Remote-User: rgautam
+</verbatim>
+---+++ Result
+<verbatim>
+{
+ "entity": [
+ {
+ "name" : "SampleOutput",
+ "type" : "feed",
+ "status": "RUNNING"
+ },
+ {
+ "name": "SampleInput",
+ "type": "feed",
+ "status": "RUNNING"
+ }
+ ]
+}
+</verbatim>
+
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/docs/src/site/twiki/restapi/ResourceList.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/ResourceList.twiki b/docs/src/site/twiki/restapi/ResourceList.twiki
index f17cb1a..b9ec4b6 100644
--- a/docs/src/site/twiki/restapi/ResourceList.twiki
+++ b/docs/src/site/twiki/restapi/ResourceList.twiki
@@ -23,7 +23,7 @@
| DELETE | [[EntityDelete][api/entities/delete/:entity-type/:entity-name]] | Delete the entity |
| GET | [[EntityStatus][api/entities/status/:entity-type/:entity-name]] | Get the status of the entity |
| GET | [[EntityDefinition][api/entities/definition/:entity-type/:entity-name]] | Get the definition of the entity |
-| GET | [[EntityList][api/entities/list/:entity-type]] | Get the list of entities |
+| GET | [[EntityList][api/entities/list/:entity-type?fields=:fields]] | Get the list of entities |
| GET | [[EntityDependencies][api/entities/dependencies/:entity-type/:entity-name]] | Get the dependencies of the entity |
---++ REST Call on Feed and Process Instances
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/css/falcon.css
----------------------------------------------------------------------
diff --git a/html5-ui/css/falcon.css b/html5-ui/css/falcon.css
new file mode 100644
index 0000000..f72b1ad
--- /dev/null
+++ b/html5-ui/css/falcon.css
@@ -0,0 +1,138 @@
+/*
+* 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.
+*/
+
+.falcon-brand {
+ padding-left: 40px;
+ background-image: url('../img/falcon-64.png');
+ background-size: 40px 40px;
+ background-repeat: no-repeat;
+ background-position: left center;
+}
+
+.btn-entity-list {
+ cursor: pointer;
+}
+
+.link-icons:before {
+ position: relative;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ -webkit-font-smoothing: antialiased;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ padding-right: 0.4em;
+ vertical-align: -20%;
+ font-size: 120%;
+}
+
+.entity-title:before {
+ color: #428bca;
+ vertical-align: -20%;
+}
+
+.entity-link-cluster:before {
+ content: "\2601";
+}
+
+.entity-link-process:before {
+ content: "\e110";
+}
+
+.entity-link-feed:before {
+ content: "\e181";
+}
+
+#entity-paginator {
+ text-align: right;
+}
+
+.instance-icons:before {
+ position: relative;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ -webkit-font-smoothing: antialiased;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ padding-right: 0.3em;
+ font-size: 100%;
+ vertical-align: top;
+}
+
+.instance-link-SUCCEEDED:before {
+ color: green;
+ content: "\e013";
+}
+
+.instance-link-RUNNING:before {
+ color: green;
+ content: "\e072";
+}
+
+.instance-link-WAITING:before {
+ color: orange;
+ content: "\e023";
+}
+
+.instance-link-FAILED:before {
+ color: red;
+ content: "\e014";
+}
+
+.node-name:before {
+ font-family: 'Glyphicons Halflings';
+ -webkit-font-smoothing: antialiased;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ padding-right: 0.3em;
+ vertical-align: -20%;
+ font-size: 110%;
+ color: #428bca;
+}
+
+.node-name-cluster:before {
+ content: "\2601";
+}
+
+.node-name-process:before {
+ content: "\e110";
+}
+
+.node-name-feed:before {
+ content: "\e181";
+}
+
+.node rect {
+ stroke-width: 0.5px;
+ stroke: #999;
+ fill: #ffffff;
+ fill-opacity: 80%;
+}
+
+.edge path {
+ fill: none;
+ stroke: #333;
+ stroke-width: 1px;
+}
+
+.node-name {
+ vertical-align: middle;
+ margin: 10px;
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/entity.html
----------------------------------------------------------------------
diff --git a/html5-ui/entity.html b/html5-ui/entity.html
new file mode 100644
index 0000000..1032187
--- /dev/null
+++ b/html5-ui/entity.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!--
+ 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.
+-->
+<meta charset="utf-8" />
+<title>Apache Falcon</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<meta name="description" content="" />
+<meta name="author" content="" />
+<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.1/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
+<link href="css/falcon.css" type="text/css" rel="stylesheet" />
+<link rel="apple-touch-icon-precomposed" sizes="144x144" href="img/falcon-144.png" />
+<link rel="apple-touch-icon-precomposed" sizes="114x114" href="img/falcon-114.png" />
+<link rel="apple-touch-icon-precomposed" sizes="72x72" href="img/falcon-72.png" />
+<link rel="apple-touch-icon-precomposed" href="img/falcon-57.png" />
+<link rel="shortcut icon" href="img/favicon.png" />
+</head>
+<body>
+<div class="navbar navbar-default">
+<div class="navbar-header"><button type="button" class="navbar-toggle" data-toggle="collapse" data-target=
+".navbar-collapse"></button> <a class="navbar-brand falcon-brand">Falcon Server</a></div>
+<div class="navbar-collapse navbar-right collapse">
+<ul class="nav navbar-nav">
+<li><a class="btn-entity-list" href="index.html?type=feed">Data sets</a></li>
+<li><a class="btn-entity-list" href="index.html?type=process">Processes</a></li>
+<li><a class="btn-entity-list" href="index.html?type=cluster">Clusters</a></li>
+</ul>
+</div>
+</div>
+<div class="container">
+
+<h3 class="link-icons entity-title" id="entity-title"></h3>
+<br />
+<div id="entity-info-container">
+<div class="panel panel-default" id="panel-instance" style="display:none">
+<div class="panel-heading">Instances</div>
+<div class="panel-body"></div>
+</div>
+<div class="panel panel-default" id="panel-definition">
+<div class="panel-heading">Definition</div>
+<div class="panel-body"> <textarea class="form-control" id="entity-def-textarea"></textarea></div>
+</div>
+<div class="panel panel-default" id="panel-dependency" style="display:none">
+<div class="panel-heading">
+Dependency
+</div>
+<div class="panel-body">
+<div id="dep-view-list" style="display:none"></div>
+<div id="dep-view-graph" style="display:none"></div>
+</div>
+<div class="panel-footer">
+<div class="btn-group">
+<button class="btn btn-primary" id="btn-dep-list">List view</button>
+<button class="btn btn-default" id="btn-dep-graph">Graph view</button>
+</div>
+</div>
+</div>
+</div>
+<hr />
+<div class="footer">© Apache Falcon, 2013</div>
+</div>
+<!-- /container -->
+<script id="dependency-tmpl" type="text/x-dust-template">
+<table class="table table-bordered">
+ <tbody>
+ {#entity}
+ <tr><td><a class="link-icons entity-link-{type}" href="entity.html?type={type}&id={name}">{name}</a></td></tr>
+ {/entity}
+ </tbody>
+</table>
+</script><script id="instance-tmpl" type="text/x-dust-template">
+<table class="table">
+ <tbody>
+ {#instances}
+ <tr>
+ <td><span class="instance-icons instance-link-{status}"></span> {instance}</td>
+ <td style="width: 6em; text-align: right">
+ {?logFile}<a href="{logFile}" target="_blank">Logs</a>{/logFile}
+ {?details}<a style="cursor: pointer" class="instance-hdfs-log" data-toggle="tooltip" data-title="<div style='word-break:break-all;'>Log available at {details}</div>" data-html="true" data-trigger="click"><span class="glyphicon glyphicon-export"></span></a>{/details}
+ </td>
+ </tr>
+ {/instances}
+ </tbody>
+</table>
+</script><script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript">
+</script><script src="//netdna.bootstrapcdn.com/bootstrap/3.0.1/js/bootstrap.min.js" type="text/javascript">
+</script><script src="//cdnjs.cloudflare.com/ajax/libs/dustjs-linkedin/2.0.0/dust-full.min.js" type="text/javascript">
+</script><script src="http://d3js.org/d3.v3.min.js" charset="utf-8">
+</script><script src="//cpettitt.github.io/project/dagre/latest/dagre.min.js" type="text/javascript">
+</script><script src="js/falcon.js" type="text/javascript">
+</script><script src="js/falcon-entity.js" type="text/javascript">
+</script>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/falcon-114.png
----------------------------------------------------------------------
diff --git a/html5-ui/img/falcon-114.png b/html5-ui/img/falcon-114.png
new file mode 100644
index 0000000..8185dde
Binary files /dev/null and b/html5-ui/img/falcon-114.png differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/falcon-144.png
----------------------------------------------------------------------
diff --git a/html5-ui/img/falcon-144.png b/html5-ui/img/falcon-144.png
new file mode 100644
index 0000000..0b4cc00
Binary files /dev/null and b/html5-ui/img/falcon-144.png differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/falcon-57.png
----------------------------------------------------------------------
diff --git a/html5-ui/img/falcon-57.png b/html5-ui/img/falcon-57.png
new file mode 100644
index 0000000..f5643c6
Binary files /dev/null and b/html5-ui/img/falcon-57.png differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/falcon-64.png
----------------------------------------------------------------------
diff --git a/html5-ui/img/falcon-64.png b/html5-ui/img/falcon-64.png
new file mode 100644
index 0000000..bda8906
Binary files /dev/null and b/html5-ui/img/falcon-64.png differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/falcon-72.png
----------------------------------------------------------------------
diff --git a/html5-ui/img/falcon-72.png b/html5-ui/img/falcon-72.png
new file mode 100644
index 0000000..4f4bc20
Binary files /dev/null and b/html5-ui/img/falcon-72.png differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/falcon.png
----------------------------------------------------------------------
diff --git a/html5-ui/img/falcon.png b/html5-ui/img/falcon.png
new file mode 100644
index 0000000..be66974
Binary files /dev/null and b/html5-ui/img/falcon.png differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/falcon.xcf
----------------------------------------------------------------------
diff --git a/html5-ui/img/falcon.xcf b/html5-ui/img/falcon.xcf
new file mode 100644
index 0000000..4bc14b8
Binary files /dev/null and b/html5-ui/img/falcon.xcf differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/img/favicon.png
----------------------------------------------------------------------
diff --git a/html5-ui/img/favicon.png b/html5-ui/img/favicon.png
new file mode 100644
index 0000000..bda8906
Binary files /dev/null and b/html5-ui/img/favicon.png differ
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/index.html
----------------------------------------------------------------------
diff --git a/html5-ui/index.html b/html5-ui/index.html
new file mode 100644
index 0000000..47f2a3b
--- /dev/null
+++ b/html5-ui/index.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!--
+ 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.
+-->
+<meta charset="utf-8" />
+<title>Apache Falcon</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<meta name="description" content="" />
+<meta name="author" content="" />
+<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.1/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
+<link href="css/falcon.css" type="text/css" rel="stylesheet" />
+<link rel="apple-touch-icon-precomposed" sizes="144x144" href="img/falcon-144.png" />
+<link rel="apple-touch-icon-precomposed" sizes="114x114" href="img/falcon-114.png" />
+<link rel="apple-touch-icon-precomposed" sizes="72x72" href="img/falcon-72.png" />
+<link rel="apple-touch-icon-precomposed" href="img/falcon-57.png" />
+<link rel="shortcut icon" href="img/favicon.png" />
+</head>
+<body>
+<div class="navbar navbar-default">
+<div class="navbar-header"><button type="button" class="navbar-toggle" data-toggle="collapse" data-target=
+".navbar-collapse"></button> <a class="navbar-brand falcon-brand">Falcon Server</a></div>
+<div class="navbar-collapse navbar-right collapse">
+<ul class="nav navbar-nav">
+<li><a class="btn-entity-list" data-entity-type="feed" href="index.html?type=feed">Data sets</a></li>
+<li><a class="btn-entity-list" data-entity-type="process" href="index.html?type=process">Processes</a></li>
+<li><a class="btn-entity-list" data-entity-type="cluster" href="index.html?type=cluster">Clusters</a></li>
+</ul>
+</div>
+</div>
+<div class="container">
+<div id="entity-list-container"></div>
+<div id="entity-paginator"></div>
+<hr />
+<div class="footer">© Apache Falcon, 2013</div>
+</div>
+<!-- /container -->
+<script id="entity-list-tmpl" type="text/x-dust-template">
+<table class="table table-striped table-bordered" id="entity-list">
+ <thead>
+ <th>Name</th><th style="width:10em; text-align: center">Status</th>
+ </thead>
+ <tbody>
+ {#entity}
+ <tr>
+ <td><a class="link-icons entity-link-{type}" href="entity.html?type={type}&id={name}">{name}</a></td>
+ <td style="text-align: center">{status}</td>
+ </tr>
+ {/entity}
+ </tbody>
+</table>
+</script><script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript">
+</script><script src="//netdna.bootstrapcdn.com/bootstrap/3.0.1/js/bootstrap.min.js" type="text/javascript">
+</script><script src="//cdnjs.cloudflare.com/ajax/libs/dustjs-linkedin/2.0.0/dust-full.min.js" type="text/javascript">
+</script><script src="js/falcon.js" type="text/javascript">
+</script><script src="js/falcon-index.js" type="text/javascript">
+</script>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/js/falcon-entity.js
----------------------------------------------------------------------
diff --git a/html5-ui/js/falcon-entity.js b/html5-ui/js/falcon-entity.js
new file mode 100644
index 0000000..de2eae5
--- /dev/null
+++ b/html5-ui/js/falcon-entity.js
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+(function(falcon, dust) {
+ var TYPE_MAP = {
+ "feed": "Data set",
+ "process": "Process",
+ "cluster": "Cluster"
+ };
+
+ dust.loadSource(dust.compile($('#dependency-tmpl').html(), 'dependency'));
+ dust.loadSource(dust.compile($('#instance-tmpl').html(), 'instance'));
+
+ var entityType = (/type=(.+?)(&|$)/.exec(location.search)||[,null])[1];
+ var entityId = (/id=(.+?)(&|$)/.exec(location.search)||[,null])[1];
+
+ function url(type) {
+ return 'api/' + type + '/' + entityType + '/' + entityId;
+ }
+
+ $('#breadcrumb-type').text(TYPE_MAP[entityType]);
+ $('#entity-title').addClass('entity-link-' + entityType)
+ .text(entityId + ' ')
+ .append('<span class="label label-success">' + TYPE_MAP[entityType] + '</span>');
+
+ function switchDependencyView(to_shown) {
+ var orig = to_shown === 'list' ? 'graph' : 'list';
+ $('#dep-view-' + orig).hide();
+ $('#btn-dep-' + orig).addClass('btn-default').removeClass('btn-primary');
+ $('#dep-view-' + to_shown).show();
+ $('#btn-dep-' + to_shown).addClass('btn-primary').removeClass('btn-default');
+ }
+
+ function loadInstance(start, end) {
+ falcon.getJson(url('instance/status') + '?start=' + start + '&end=' + end, function (data) {
+ if (data.instances == null)
+ return;
+
+ if (!($.isArray(data.instances)))
+ data.instances = new Array(data.instances);
+
+ dust.render('instance', data, function(err, out) {
+ $('#panel-instance > .panel-body').html(out);
+ $('.instance-hdfs-log').tooltip();
+ $('#panel-instance').show();
+ });
+ });
+ }
+
+ function loadDependency() {
+ falcon.getJson(url('entities/dependencies'), function (data) {
+ if (data.entity == null)
+ return;
+
+ if (!($.isArray(data.entity)))
+ data.entity = new Array(data.entity);
+
+ data.entity.sort(function(l,r) {
+ var a = l.type, b = r.type;
+ return a < b ? -1 : (a > b ? 1 : 0);
+ });
+
+ dust.render('dependency', data, function(err, out) {
+ $('#dep-view-list').html(out);
+ switchDependencyView('list');
+ $('#panel-dependency').show();
+ });
+ });
+ }
+
+ function load() {
+ var isCluster = entityType === 'cluster';
+
+ falcon.getText(url('entities/definition'), function (data) {
+ $('#entity-def-textarea')
+ .attr('rows', data.match(/\n/g).length + 1)
+ .text(data);
+
+ if (!isCluster) {
+ var xml = $.parseXML(data);
+ var e = $(xml).find('validity');
+ if (e != null) {
+ loadInstance(e.attr('start'), e.attr('end'));
+ }
+ }
+ });
+
+ if (!isCluster) {
+ loadDependency();
+ }
+ }
+
+ /**
+ * Plot dependency graph in SVG format
+ **/
+ function plotDependencyGraph(nodes, svg) {
+ var NODE_WIDTH = 150;
+ var NODE_HEIGHT = 60;
+ var RECT_ROUND = 5;
+ var SEPARATION = 40;
+
+ // Function to draw the lines of the edge
+ var LINE_FUNCTION = d3.svg.line()
+ .x(function(d) { return d.x; })
+ .y(function(d) { return d.y; })
+ .interpolate('basis');
+
+ // Mappining from id to a node
+ var node_by_id = {};
+
+ var layout = null;
+
+ /**
+ * Calculate the intersection point between the point p and the edges of the rectangle rect
+ **/
+ function intersectRect(rect, p) {
+ var cx = rect.x, cy = rect.y, dx = p.x - cx, dy = p.y - cy, w = rect.width / 2, h = rect.height / 2;
+
+ if (dx == 0)
+ return { "x": p.x, "y": rect.y + (dy > 0 ? h : -h) };
+
+ var slope = dy / dx;
+
+ var x0 = null, y0 = null;
+ if (Math.abs(slope) < rect.height / rect.width) {
+ // intersect with the left or right edges of the rect
+ x0 = rect.x + (dx > 0 ? w : -w);
+ y0 = cy + slope * (x0 - cx);
+ } else {
+ y0 = rect.y + (dy > 0 ? h : -h);
+ x0 = cx + (y0 - cy) / slope;
+ }
+
+ return { "x": x0, "y": y0 };
+ }
+
+ function drawNode(u, value) {
+ var root = svg.append('g').classed('node', true)
+ .attr('transform', 'translate(' + -value.width/2 + ',' + -value.height/2 + ')');
+ var node = node_by_id[u];
+
+ var rect = root.append('rect')
+ .attr('width', value.width)
+ .attr('height', value.height)
+ .attr('x', value.x)
+ .attr('y', value.y)
+ .attr('rx', RECT_ROUND)
+ .attr('ry', RECT_ROUND);
+
+ var fo = root.append('foreignObject')
+ .attr('x', value.x)
+ .attr('y', value.y)
+ .attr('width', value.width)
+ .attr('height', value.height);
+
+ var txt = fo.append('xhtml:div')
+ .text(node.name)
+ .classed('node-name', true)
+ .classed('node-name-' + node.type, true);
+ }
+
+ function drawEdge(e, u, v, value) {
+ var root = svg.append('g').classed('edge', true);
+
+ root.append('path')
+ .attr('marker-end', 'url(#arrowhead)')
+ .attr('d', function() {
+ var points = value.points;
+
+ var source = layout.node(u);
+ var target = layout.node(v);
+
+ var p0 = points.length === 0 ? target : points[0];
+ var p1 = points.length === 0 ? source : points[points.length - 1];
+
+ points.unshift(intersectRect(source, p0));
+ points.push(intersectRect(target, p1));
+
+ return LINE_FUNCTION(points);
+ });
+ }
+
+ function postRender() {
+ svg
+ .append('svg:defs')
+ .append('svg:marker')
+ .attr('id', 'arrowhead')
+ .attr('viewBox', '0 0 10 10')
+ .attr('refX', 8)
+ .attr('refY', 5)
+ .attr('markerUnits', 'strokewidth')
+ .attr('markerWidth', 8)
+ .attr('markerHeight', 5)
+ .attr('orient', 'auto')
+ .attr('style', 'fill: #333')
+ .append('svg:path')
+ .attr('d', 'M 0 0 L 10 5 L 0 10 z');
+ }
+
+ function plot() {
+ var g = new dagre.Digraph();
+
+ for (var key in nodes) {
+ var n = nodes[key];
+ node_by_id[n.id] = n;
+ g.addNode(n.id, { "width": NODE_WIDTH, "height": NODE_HEIGHT });
+ }
+
+ for (var key in nodes) {
+ var n = nodes[key];
+ for (var i = 0, l = n.dependency.length; i < l; ++i) {
+ var d = n.dependency[i];
+ g.addEdge(null, d, n.id);
+ }
+ }
+
+ layout = dagre.layout()
+ .universalSep(100).rankSep(SEPARATION)
+ .run(g);
+ layout.eachEdge(drawEdge);
+ layout.eachNode(drawNode);
+
+ var bb = layout.graph().bbox;
+
+ $('#entity-dep-graph').attr('width', bb.width);
+ $('#entity-dep-graph').attr('height', bb.height);
+ postRender();
+ }
+ plot();
+ }
+
+
+ function visualizeDependencyGraph() {
+ $('#dep-view-graph')
+ .css('text-align', 'center')
+ .html('<svg id="entity-dep-graph" height="200"><g></g></svg>');
+
+ falcon.loadDependencyGraph(entityType, entityId, function(nodes) {
+ plotDependencyGraph(nodes, d3.select('#entity-dep-graph'));
+ switchDependencyView('graph');
+ });
+ }
+
+ $('#btn-dep-list').click(function() {
+ switchDependencyView('list');
+ });
+ $('#btn-dep-graph').click(visualizeDependencyGraph);
+ load();
+})(falcon, dust);
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/js/falcon-index.js
----------------------------------------------------------------------
diff --git a/html5-ui/js/falcon-index.js b/html5-ui/js/falcon-index.js
new file mode 100644
index 0000000..aa5e7a2
--- /dev/null
+++ b/html5-ui/js/falcon-index.js
@@ -0,0 +1,107 @@
+/*
+* 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.
+*/
+(function (falcon, dust) {
+ var ENTRIES_PER_PAGE = 25;
+
+ var source = $("#entity-list-tmpl").html();
+ dust.loadSource(dust.compile(source, 'entity-list'));
+
+ var entityType = (/type=(.+?)(&|$)/.exec(location.search)||[,'feed'])[1];
+
+ function gotoPage(page) {
+ var start = (page - 1) * ENTRIES_PER_PAGE, end = page * ENTRIES_PER_PAGE;
+
+ var d = falcon.entities.slice(start, end);
+ dust.render('entity-list', {"entity": d}, function(err, out) {
+ var total = Math.ceil(falcon.entities.length / ENTRIES_PER_PAGE);
+ $('#entity-paginator').data('activePage', page);
+ generatePaginator(page, total);
+
+ $('#entity-list-container').html(out);
+ });
+ }
+
+ function generatePaginator(current, total) {
+ var root = $('<ul class="pagination"></ul>'),
+ prev = $('<li><a href="#">«</a></li>'),
+ next = $('<li><a href="#">»</a></li>');
+
+ root.append(prev);
+ for (var i = 1; i <= total; ++i) {
+ var l = $('<li><a href="#">' + i + '</a></li>')
+ .attr('data-page', i);
+
+ if (i == current)
+ l.addClass('active');
+
+ root.append(l);
+ }
+
+ root.append(next);
+
+ if (current == 1) {
+ prev.addClass('disabled');
+ } else {
+ prev.attr('data-page', current - 1);
+ }
+
+ if (current == total) {
+ next.addClass('disabled');
+ } else {
+ next.attr('data-page', current + 1);
+ }
+
+ root.children()
+ .click(function() {
+ var n = $(this).attr('data-page');
+ if (n !== undefined)
+ gotoPage(n);
+
+ return false;
+ });
+ $('#entity-paginator').html(root);
+ }
+
+ /**
+ * Gets the latest entities from '/entities/list/process',
+ * 'entities/list/feed', '/entities/list/cluster'
+ **/
+ function refreshEntities(type) {
+ falcon.getJson('api/entities/list/' + type + '?fields=status', function (data) {
+ if (data.entity == null)
+ return;
+
+ if (!($.isArray(data.entity)))
+ data.entity = new Array(data.entity);
+
+ $('#entity-paginator').data('activePage', 1);
+ falcon.entities = data.entity;
+ gotoPage(1);
+ });
+ }
+
+ function initialize() {
+ $('.btn-entity-list').click(function() {
+ $(this).parent().siblings().removeClass('active');
+ $(this).parent().addClass('active');
+ refreshEntities($(this).attr('data-entity-type'));
+ });
+ $('.btn-entity-list[data-entity-type="' + entityType + '"]').click();
+ }
+
+ initialize();
+})(falcon, dust);
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/html5-ui/js/falcon.js
----------------------------------------------------------------------
diff --git a/html5-ui/js/falcon.js b/html5-ui/js/falcon.js
new file mode 100644
index 0000000..14758bc
--- /dev/null
+++ b/html5-ui/js/falcon.js
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+(function(exports) {
+ "use strict";
+
+ var USER_ID = 'admin';
+
+ function onError (msg) {
+ alert(msg);
+ }
+
+ function ajax_impl(options) {
+ $.extend(options, {'headers': { 'Remote-User': USER_ID }});
+ return $.ajax(options);
+ }
+
+ function getJson_impl(url, success) {
+ return ajax_impl({
+ 'dataType': 'json',
+ 'url': url,
+ 'success': success
+ });
+ }
+
+ function getText_impl(url, success) {
+ return ajax_impl({
+ 'dataType': 'text',
+ 'url': url,
+ 'success': success
+ });
+ }
+
+ var falcon = {
+ loadTemplate: function(tmpl_name, url, success) {
+ $.get(url, function (data) {
+ dust.loadSource(dust.compile(data, tmpl_name));
+ success();
+ }).fail(function() { onError('Cannot load the application.'); });
+ },
+
+ ajax: ajax_impl,
+ getJson: getJson_impl,
+ getText: getText_impl,
+
+ /**
+ * Calling the REST API recursively to get the dependency graph
+ **/
+ loadDependencyGraph: function(entity_type, entity_name, done_callback) {
+ var nodes = {};
+ var next_node_id = 0;
+
+ var STATE_UNINITIALIZED = 0;
+ var STATE_REQUEST_SENT = 1;
+
+ var requests_in_fly = 0;
+
+ function key(type, name) {
+ return type + '/' + name;
+ }
+
+ function getOrCreateNode(type, name) {
+ var k = key(type, name);
+ if (nodes[k] !== undefined)
+ return nodes[k];
+
+ var n = {
+ "request_state": STATE_UNINITIALIZED,
+ "id": next_node_id++,
+ "type": type,
+ "name": name,
+ "dependency": []
+ };
+ nodes[k] = n;
+ return n;
+ }
+
+ function loadEntry(node) {
+ var type = node.type, name = node.name, k = key(type, name);
+ getJson_impl(
+ 'api/entities/dependencies/' + type + '/' + name,
+ function (data) {
+ if (data.entity == null)
+ return;
+
+ if (!($.isArray(data.entity)))
+ data.entity = new Array(data.entity);
+
+ var l = data.entity.length;
+ for (var i = 0; i < l; ++i) {
+ var e = data.entity[i];
+ node.dependency.push(getOrCreateNode(e.type, e.name).id);
+ enqueue(e.type, e.name);
+ }
+ })
+ .always(function () {
+ --requests_in_fly;
+
+ if (requests_in_fly == 0)
+ done_callback(nodes);
+ });
+ }
+
+ function enqueue(type, name) {
+ // There's no dependency for clusters
+ if (type === 'cluster')
+ return;
+
+ var k = key(type, name);
+
+ if (nodes[k] !== undefined && nodes[k].request_state !== STATE_UNINITIALIZED)
+ return;
+
+ var n = getOrCreateNode(type, name);
+ n.request_state = STATE_REQUEST_SENT;
+
+ ++requests_in_fly;
+ loadEntry(n);
+ }
+
+ enqueue(entity_type, entity_name);
+ }
+ };
+
+ exports.falcon = falcon;
+})(window);
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 091db4d..c05de77 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1018,6 +1018,7 @@
<exclude>**/data.txt</exclude>
<exclude>**/maven-eclipse.xml</exclude>
<exclude>**/.externalToolBuilders/**</exclude>
+ <exclude>html5-ui/**</exclude>
</excludes>
<argLine>-Dfalcon.log.dir=target/logs -Dfalcon.embeddedmq.data=target/data</argLine>
</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/prism/pom.xml
----------------------------------------------------------------------
diff --git a/prism/pom.xml b/prism/pom.xml
index 2d78ffd..2ca6330 100644
--- a/prism/pom.xml
+++ b/prism/pom.xml
@@ -134,8 +134,13 @@
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
- <version>2.1.1</version>
+ <version>2.4</version>
<configuration>
+ <webResources>
+ <resource>
+ <directory>../html5-ui</directory>
+ </resource>
+ </webResources>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/9e376c20/webapp/pom.xml
----------------------------------------------------------------------
diff --git a/webapp/pom.xml b/webapp/pom.xml
index 02c0458..e14b261 100644
--- a/webapp/pom.xml
+++ b/webapp/pom.xml
@@ -184,10 +184,13 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
- <version>2.1.1</version>
+ <version>2.4</version>
<configuration>
<webResources>
<resource>
+ <directory>../html5-ui</directory>
+ </resource>
+ <resource>
<directory>src/main/webapp/WEB-INF/embedded</directory>
<targetPath>WEB-INF</targetPath>
</resource>
@@ -400,14 +403,14 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
- <version>2.1.1</version>
+ <version>2.4</version>
<configuration>
<packagingExcludes>WEB-INF/classes/deploy.properties</packagingExcludes>
<webResources>
- <resource>
- <directory>src/main/webapp/WEB-INF/distributed</directory>
- <targetPath>WEB-INF</targetPath>
- </resource>
+ <resource>
+ <directory>src/main/webapp/WEB-INF/distributed</directory>
+ <targetPath>WEB-INF</targetPath>
+ </resource>
</webResources>
</configuration>
</plugin>