diff --git oak-core/pom.xml oak-core/pom.xml
index 882ae83..672b794 100644
--- oak-core/pom.xml
+++ oak-core/pom.xml
@@ -40,6 +40,7 @@
           <instructions>
             <Import-Package>
               com.mongodb*;version="[2.14, 4)";resolution:=optional,
+              org.apache.felix.inventory;version="[1.0.0, 2)";resolution:=optional,
               *
             </Import-Package>
             <Export-Package>
@@ -99,6 +100,10 @@
             <DynamicImport-Package>
               org.apache.felix.jaas.boot
             </DynamicImport-Package>
+            <Private-Package>
+              {local-packages},
+              org.apache.felix.inventory
+            </Private-Package>
           </instructions>
         </configuration>
       </plugin>
@@ -268,6 +273,13 @@
       <artifactId>slf4j-api</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.inventory</artifactId>
+      <version>1.0.4</version>
+      <optional>true</optional>
+    </dependency>
+
     <!-- Findbugs annotations -->
     <dependency>
       <groupId>com.google.code.findbugs</groupId>
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexDefinitionPrinter.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexDefinitionPrinter.java
new file mode 100644
index 0000000..bf88748
--- /dev/null
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexDefinitionPrinter.java
@@ -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.jackrabbit.oak.plugins.index;
+
+import java.io.PrintWriter;
+
+import org.apache.felix.inventory.Format;
+import org.apache.felix.inventory.InventoryPrinter;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
+import org.apache.jackrabbit.oak.commons.json.JsopWriter;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+
+@Component
+@Service
+@Properties({
+        @Property(name = "felix.inventory.printer.name", value = "oak-index-defn"),
+        @Property(name = "felix.inventory.printer.title", value = "Oak Index Definitions"),
+        @Property(name = "felix.inventory.printer.format", value = {"JSON"})
+})
+public class IndexDefinitionPrinter implements InventoryPrinter {
+
+    @Reference
+    private IndexPathService indexPathService;
+
+    @Reference
+    private NodeStore nodeStore;
+
+    public IndexDefinitionPrinter() {
+    }
+
+    public IndexDefinitionPrinter(NodeStore nodeStore, IndexPathService indexPathService) {
+        this.indexPathService = indexPathService;
+        this.nodeStore = nodeStore;
+    }
+
+    @Override
+    public void print(PrintWriter printWriter, Format format, boolean isZip) {
+        if (format == Format.JSON) {
+            NodeState root = nodeStore.getRoot();
+            JsopWriter json = new JsopBuilder();
+            json.object();
+            for (String indexPath : indexPathService.getIndexPaths()) {
+                json.key(indexPath);
+                NodeState idxState = NodeStateUtils.getNode(root, indexPath);
+                NodeStateJsonUtils.copyAsJson(json, idxState, false);
+            }
+            json.endObject();
+            printWriter.print(JsopBuilder.prettyPrint(json.toString()));
+        }
+    }
+}
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfo.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfo.java
new file mode 100644
index 0000000..0a417b1
--- /dev/null
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfo.java
@@ -0,0 +1,85 @@
+/*
+ * 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.jackrabbit.oak.plugins.index;
+
+import javax.annotation.CheckForNull;
+
+import aQute.bnd.annotation.ProviderType;
+
+/**
+ * Captures information related to index
+ */
+@ProviderType
+public interface IndexInfo {
+    /**
+     * Returns paths of index definition in the repository
+     */
+    String getIndexPath();
+
+    /**
+     * Returns type of index definition like 'property' or 'lucene'
+     */
+    String getType();
+
+    /**
+     * Returns name of the async index lane to which this index is bound to
+     * or null if its not an async index
+     */
+    @CheckForNull
+    String getAsyncName();
+
+    /**
+     * Time in millis at which index was last updated
+     *
+     * @return time in millis or -1 if unknown
+     */
+    long getLastUpdatedTime();
+
+    /**
+     * Returns time in millis of the repository state upto which index is upto
+     * date. This may or may not be same as {@code #getLastUpdatedTime}. For e.g.
+     * consider an index at /oak:index/fooIndex bound to async lane "async".
+     * The index might have got updated 2 cycle ago when async indexer traversed content
+     * node which were indexed by this index and it was not updated in last index cycle.
+     * Then {@code indexedUptoTime} would be the time of last complete cycle while
+     * {@code lastUpdatedTime} would the time of 2nd last cycle
+     *
+     * @return time in millis or -1 if unknown
+     */
+    long getIndexedUptoTime();
+
+    /**
+     * An estimate of entry count in the index
+     */
+    long getEstimatedEntryCount();
+
+    /**
+     * Index data storage size
+
+     * @return storage size or -1 if unknown
+     */
+    long getSizeInBytes();
+
+    /**
+     * Determines if index definition has changed but no reindexing
+     * was done for that change.
+     */
+    boolean hasIndexDefinitionChangedWithoutReindexing();
+}
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoProvider.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoProvider.java
new file mode 100644
index 0000000..f84ca87
--- /dev/null
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoProvider.java
@@ -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.jackrabbit.oak.plugins.index;
+
+import java.io.IOException;
+
+import javax.annotation.CheckForNull;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * Service to be provided by various index implementations.
+ * This would then be used by {@code IndexInfoService}
+ * for collecting information related to index.
+ */
+@ConsumerType
+public interface IndexInfoProvider {
+
+    /**
+     * Index type for this implementation can provide information
+     */
+    String getType();
+
+    @CheckForNull
+    IndexInfo getInfo(String indexPath) throws IOException;
+
+    /**
+     * Determined if the index is valid and usable. If the index is corrupt
+     * then it returns false
+     */
+    boolean isValid(String indexPath) throws IOException;
+}
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoService.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoService.java
new file mode 100644
index 0000000..b0f8a7c
--- /dev/null
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoService.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jackrabbit.oak.plugins.index;
+
+import java.io.IOException;
+
+import javax.annotation.CheckForNull;
+
+import aQute.bnd.annotation.ProviderType;
+
+@ProviderType
+public interface IndexInfoService {
+
+    /**
+     * Returns {@code IndexInfo} for all the indexes present in
+     * the repository
+     */
+    Iterable<IndexInfo> getAllIndexInfo();
+
+    /**
+     * Returns {@code IndexInfo} for index at given path
+     *
+     * @param indexPath path repository
+     *
+     * @return indexInfo for the index or null if there is no index node
+     * found at given path
+     */
+    @CheckForNull
+    IndexInfo getInfo(String indexPath) throws IOException;
+
+    /**
+     * Determined if the index is valid and usable. If the index is corrupt
+     * then it returns false
+     */
+    boolean isValid(String indexPath) throws IOException;
+}
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoServiceImpl.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoServiceImpl.java
new file mode 100644
index 0000000..5145102
--- /dev/null
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoServiceImpl.java
@@ -0,0 +1,169 @@
+/*
+ * 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.jackrabbit.oak.plugins.index;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.ReferencePolicyOption;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.notNull;
+
+@Component
+@Service
+public class IndexInfoServiceImpl implements IndexInfoService{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference
+    private IndexPathService indexPathService;
+
+    @Reference(policy = ReferencePolicy.DYNAMIC,
+            cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
+            policyOption = ReferencePolicyOption.GREEDY,
+            referenceInterface = IndexInfoProvider.class
+    )
+    private final Map<String, IndexInfoProvider> infoProviders = new ConcurrentHashMap<>();
+
+    @Reference
+    private NodeStore nodeStore;
+
+    @Override
+    public Iterable<IndexInfo> getAllIndexInfo() {
+        return Iterables.filter(Iterables.transform(indexPathService.getIndexPaths(), new Function<String, IndexInfo>() {
+            @Override
+            public IndexInfo apply(String indexPath) {
+                try {
+                    return getInfo(indexPath);
+                } catch (Exception e) {
+                    log.warn("Error occurred while capturing IndexInfo for path {}", indexPath, e);
+                    return null;
+                }
+            }
+        }), notNull());
+    }
+
+    @Override
+    public IndexInfo getInfo(String indexPath) throws IOException {
+        String type = getIndexType(indexPath);
+        if (type == null) return null;
+        IndexInfoProvider infoProvider = infoProviders.get(type);
+
+        if (infoProvider == null) {
+            return new SimpleIndexInfo(indexPath, type);
+        }
+
+        return infoProvider.getInfo(indexPath);
+    }
+
+    @Override
+    public boolean isValid(String indexPath) throws IOException {
+        String type = getIndexType(indexPath);
+        if (type == null){
+            log.warn("No type property defined for index definition at path {}", indexPath);
+            return false;
+        }
+        IndexInfoProvider infoProvider = infoProviders.get(type);
+        if (infoProvider == null){
+            log.warn("No IndexInfoProvider for for index definition at path {} of type {}", indexPath, type);
+            return true; //TODO Reconsider this scenario
+        }
+        return infoProvider.isValid(indexPath);
+    }
+
+    protected void bindInfoProviders(IndexInfoProvider infoProvider){
+        infoProviders.put(checkNotNull(infoProvider.getType()), infoProvider);
+    }
+
+    protected void unbindInfoProviders(IndexInfoProvider infoProvider){
+        infoProviders.remove(infoProvider.getType());
+    }
+
+    private String getIndexType(String indexPath) {
+        NodeState idxState = NodeStateUtils.getNode(nodeStore.getRoot(), indexPath);
+        String type = idxState.getString(IndexConstants.TYPE_PROPERTY_NAME);
+        if (type == null || "disabled".equals(type)){
+            return null;
+        }
+        return type;
+    }
+
+    private static class SimpleIndexInfo implements IndexInfo {
+        private final String indexPath;
+        private final String type;
+
+        private SimpleIndexInfo(String indexPath, String type) {
+            this.indexPath = indexPath;
+            this.type = type;
+        }
+
+        @Override
+        public String getIndexPath() {
+            return indexPath;
+        }
+
+        @Override
+        public String getType() {
+            return type;
+        }
+
+        @Override
+        public String getAsyncName() {
+            return null;
+        }
+
+        @Override
+        public long getLastUpdatedTime() {
+            return -1;        }
+
+        @Override
+        public long getIndexedUptoTime() {
+            return -1;
+        }
+
+        @Override
+        public long getEstimatedEntryCount() {
+            return -1;
+        }
+
+        @Override
+        public long getSizeInBytes() {
+            return -1;
+        }
+
+        @Override
+        public boolean hasIndexDefinitionChangedWithoutReindexing() {
+            return false;
+        }
+    }
+}
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexPrinter.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexPrinter.java
new file mode 100644
index 0000000..8c19eff
--- /dev/null
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexPrinter.java
@@ -0,0 +1,131 @@
+/*
+ * 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.jackrabbit.oak.plugins.index;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ListMultimap;
+import org.apache.felix.inventory.Format;
+import org.apache.felix.inventory.InventoryPrinter;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.api.jmx.IndexStatsMBean;
+import org.apache.jackrabbit.oak.commons.IOUtils;
+
+@Component
+@Service
+@Properties({
+        @Property(name = "felix.inventory.printer.name", value = "oak-index-stats"),
+        @Property(name = "felix.inventory.printer.title", value = "Oak Index Stats"),
+        @Property(name = "felix.inventory.printer.format", value = { "TEXT"})
+})
+public class IndexPrinter implements InventoryPrinter {
+
+    @Reference
+    private IndexInfoService indexInfoService;
+
+    @Reference
+    private AsyncIndexInfoService asyncIndexInfoService;
+
+    @Override
+    public void print(PrintWriter pw, Format format, boolean isZip) {
+        //TODO Highlight if failing
+        printAsyncIndexInfo(pw);
+        printIndexInfo(pw);
+    }
+
+    private void printAsyncIndexInfo(PrintWriter pw) {
+        List<String> asyncLanes = ImmutableList.copyOf(asyncIndexInfoService.getAsyncLanes());
+        String title = "Async Indexers State";
+        printTitle(pw, title);
+        pw.printf("Number of async indexer lanes : %d%n", asyncLanes.size());
+        pw.println();
+        for (String lane : asyncLanes) {
+            pw.println(lane);
+            AsyncIndexInfo info = asyncIndexInfoService.getInfo(lane);
+            if (info != null) {
+                        pw.printf("    Last Indexed To      : %tc%n", info.getLastIndexedTo());
+                IndexStatsMBean stats = info.getStatsMBean();
+                if (stats != null) {
+                        pw.printf("    Status              : %s%n", stats.getStatus());
+                        pw.printf("    Failing             : %s%n", stats.isFailing());
+                        pw.printf("    Paused              : %s%n", stats.isPaused());
+                    if (stats.isFailing()) {
+                        pw.printf("    Failing Since       : %s%n", stats.getFailingSince());
+                        pw.printf("    Latest Error        : %s%n", stats.getLatestError());
+                    }
+                }
+                pw.println();
+            }
+        }
+    }
+
+    private static void printTitle(PrintWriter pw, String title) {
+        pw.println(title);
+        pw.println(Strings.repeat("=", title.length()));
+    }
+
+    private void printIndexInfo(PrintWriter pw) {
+        ListMultimap<String, IndexInfo> infos = ArrayListMultimap.create();
+        for (IndexInfo info : indexInfoService.getAllIndexInfo()) {
+            infos.put(info.getType(), info);
+        }
+
+        pw.printf("Total number of indexes : %d%n", infos.size());
+        for (String type : infos.keySet()){
+            List<IndexInfo> typedInfo = infos.get(type);
+            String title = String.format("%s(%d)", type, typedInfo.size());
+            printTitle(pw, title);
+            pw.println();
+            for (IndexInfo info : typedInfo){
+                printIndexInfo(pw, info);
+            }
+        }
+    }
+
+    private static void printIndexInfo(PrintWriter pw, IndexInfo info) {
+        pw.println(info.getIndexPath());
+        pw.printf("    Type                    : %s%n", info.getType());
+        if (info.getAsyncName() != null) {
+            pw.printf("    async                   : true%n");
+            pw.printf("    async name              : %s%n", info.getAsyncName());
+        }
+
+        if (info.getIndexedUptoTime() > 0){
+            pw.printf("    Last Indexed Upto       : %tc%n", info.getIndexedUptoTime());
+        }
+
+        if (info.getSizeInBytes() > 0){
+            pw.printf("    Size                    : %s%n", IOUtils.humanReadableByteCount(info.getSizeInBytes()));
+        }
+
+        if (info.getEstimatedEntryCount() > 0){
+            pw.printf("    Estimated entry count   : %d%n", info.getEstimatedEntryCount());
+        }
+        pw.println();
+    }
+}
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/NodeStateJsonUtils.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/NodeStateJsonUtils.java
new file mode 100644
index 0000000..43b1388
--- /dev/null
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/NodeStateJsonUtils.java
@@ -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.jackrabbit.oak.plugins.index;
+
+import javax.jcr.PropertyType;
+
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
+import org.apache.jackrabbit.oak.commons.json.JsopWriter;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+
+final class NodeStateJsonUtils {
+
+    public static String toJson(NodeState state, boolean includeHiddenContent) {
+        JsopWriter json = new JsopBuilder();
+        copyAsJson(json, state, includeHiddenContent);
+        return json.toString();
+    }
+
+    public static void copyAsJson(JsopWriter json, NodeState state, boolean includeHiddenContent) {
+        json.object();
+        copyNode(state, json, includeHiddenContent);
+        json.endObject();
+    }
+
+    private static void copyNode(NodeState state, JsopWriter json, boolean includeHiddenContent) {
+        copyProperties(state, json, includeHiddenContent);
+        for (ChildNodeEntry cne : state.getChildNodeEntries()) {
+            if (!includeHiddenContent && NodeStateUtils.isHidden(cne.getName())){
+                continue;
+            }
+            json.key(cne.getName());
+            json.object();
+            copyNode(cne.getNodeState(), json, includeHiddenContent);
+            json.endObject();
+        }
+    }
+
+    private static void copyProperties(NodeState state, JsopWriter json, boolean includeHiddenContent) {
+        for (PropertyState ps : state.getProperties()) {
+            String name = ps.getName();
+            if (!includeHiddenContent && NodeStateUtils.isHidden(name)){
+                continue;
+            }
+            if (ps.isArray()) {
+                json.key(name).array();
+                for (int i = 0; i < ps.count(); i++) {
+                    copyProperty(ps, i, json);
+                }
+                json.endArray();
+            } else {
+                json.key(name);
+                copyProperty(ps, 0, json);
+            }
+        }
+    }
+
+    private static void copyProperty(PropertyState ps, int i, JsopWriter json) {
+        switch (ps.getType().tag()) {
+            case PropertyType.LONG:
+                long longVal = ps.isArray() ? ps.getValue(Type.LONG, i) : ps.getValue(Type.LONG);
+                json.value(longVal);
+                break;
+            case PropertyType.BOOLEAN:
+                boolean boolVal = ps.isArray() ? ps.getValue(Type.BOOLEAN, i) : ps.getValue(Type.BOOLEAN);
+                json.value(boolVal);
+                break;
+            case PropertyType.BINARY:
+                Blob b = ps.isArray() ? ps.getValue(Type.BINARY, i) : ps.getValue(Type.BINARY);
+                String binVal = toString(b);
+                json.value(binVal);
+                break;
+            default:
+                String strVal = ps.isArray() ? ps.getValue(Type.STRING, i) : ps.getValue(Type.STRING);
+                json.value(strVal);
+        }
+    }
+
+    private static String toString(Blob b) {
+        String id = b.getContentIdentity();
+        return id == null ? "<binary>#" + b.length() : b.getContentIdentity();
+    }
+}
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexDefinitionPrinterTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexDefinitionPrinterTest.java
new file mode 100644
index 0000000..74218e6
--- /dev/null
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexDefinitionPrinterTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.jackrabbit.oak.plugins.index;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import com.google.common.collect.Lists;
+import org.apache.felix.inventory.Format;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.json.simple.JSONValue;
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class IndexDefinitionPrinterTest {
+    private NodeStore store = new MemoryNodeStore();
+    private IndexPathService pathService = mock(IndexPathService.class);
+    private IndexDefinitionPrinter printer = new IndexDefinitionPrinter(store, pathService);
+
+    @Test
+    public void printer() throws Exception{
+        NodeBuilder builder = store.getRoot().builder();
+        builder.child("a").setProperty("foo", "bar");
+        builder.child("b").child("c").setProperty("foo", "bar");
+
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        when(pathService.getIndexPaths()).thenReturn(Lists.newArrayList("/a", "/b"));
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        printer.print(pw, Format.JSON, false);
+
+        pw.flush();
+
+        String json = sw.toString();
+
+        //If there is any error in rendered json
+        //exception would fail the test
+        JSONValue.parseWithException(json);
+    }
+}
\ No newline at end of file
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoServiceImplTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoServiceImplTest.java
new file mode 100644
index 0000000..38f44e8
--- /dev/null
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexInfoServiceImplTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.jackrabbit.oak.plugins.index;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class IndexInfoServiceImplTest {
+
+    @Rule
+    public final OsgiContext context = new OsgiContext();
+
+    private IndexInfoServiceImpl service = new IndexInfoServiceImpl();
+
+    private NodeStore store = new MemoryNodeStore();
+    private SimpleIndexPathService pathService = new SimpleIndexPathService();
+
+    @Before
+    public void setUp(){
+        context.registerService(NodeStore.class, store);
+        context.registerService(IndexPathService.class, pathService);
+        MockOsgi.injectServices(service, context.bundleContext());
+    }
+
+    @Test
+    public void indexInfo() throws Exception{
+        //1. Test Empty
+        assertNull(service.getInfo("/nonExistingPath"));
+
+        //2. Test when no backing InfoProvider
+        NodeBuilder builder = store.getRoot().builder();
+        builder.child("oak:index").child("fooIndex").setProperty("type", "foo");
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        IndexInfo info = service.getInfo("/oak:index/fooIndex");
+        assertNotNull(info);
+
+        assertEquals("/oak:index/fooIndex", info.getIndexPath());
+        assertEquals("foo", info.getType());
+
+        //3. Test when backing InfoProvider
+        IndexInfo testInfo = mock(IndexInfo.class);
+        when(testInfo.getIndexPath()).thenReturn("/some/other/path");
+
+        IndexInfoProvider infoProvider = mock(IndexInfoProvider.class);
+        when(infoProvider.getType()).thenReturn("foo");
+        when(infoProvider.getInfo(anyString())).thenReturn(testInfo);
+
+        service.bindInfoProviders(infoProvider);
+
+        IndexInfo info2 = service.getInfo("/oak:index/fooIndex");
+        assertNotNull(info2);
+        assertEquals("/some/other/path", info2.getIndexPath());
+    }
+
+    @Test
+    public void allIndexInfo() throws Exception{
+        pathService.paths = Lists.newArrayList("/oak:index/a", "/oak:index/b", "/oak:index/c", "/oak:index/d");
+
+        NodeBuilder builder = store.getRoot().builder();
+        builder.child("oak:index").child("a"); //Index with no type
+        builder.child("oak:index").child("b").setProperty("type", "type-b"); //No backing info provider
+        builder.child("oak:index").child("c").setProperty("type", "type-c"); //Info provider throws exception
+        builder.child("oak:index").child("d").setProperty("type", "type-d"); //Info provider returns result
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        IndexInfoProvider type_c = mock(IndexInfoProvider.class);
+        when(type_c.getInfo(anyString())).thenThrow(new RuntimeException());
+        when(type_c.getType()).thenReturn("type-c");
+
+        IndexInfo infod = mock(IndexInfo.class);
+        when(infod.getType()).thenReturn("type-d");
+        when(infod.getAsyncName()).thenReturn("async-d");
+
+        IndexInfoProvider type_d = mock(IndexInfoProvider.class);
+        when(type_d.getInfo(anyString())).thenReturn(infod);
+        when(type_d.getType()).thenReturn("type-d");
+
+        service.bindInfoProviders(type_c);
+        service.bindInfoProviders(type_d);
+
+        List<IndexInfo> infos = Lists.newArrayList(service.getAllIndexInfo());
+
+        //Result would only have 2 entries. One throwing exception would be ignored
+        assertEquals(2, infos.size());
+
+        for (IndexInfo info : infos) {
+            if (info.getType().equals("type-d")){
+                assertEquals("async-d", info.getAsyncName());
+            }
+        }
+
+    }
+
+    private static class SimpleIndexPathService implements IndexPathService {
+        List<String> paths = Collections.emptyList();
+
+        @Override
+        public Iterable<String> getIndexPaths() {
+            return paths;
+        }
+    }
+
+}
\ No newline at end of file
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/NodeStateJsonUtilsTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/NodeStateJsonUtilsTest.java
new file mode 100644
index 0000000..2d67989
--- /dev/null
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/NodeStateJsonUtilsTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.jackrabbit.oak.plugins.index;
+
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class NodeStateJsonUtilsTest {
+
+    @Test
+    public void toJson() throws Exception{
+        NodeBuilder builder = EMPTY_NODE.builder();
+        builder.child("a").setProperty("foo", 10);
+        builder.child("a").setProperty("foo2", "bar");
+        builder.child("a").setProperty("foo3", true);
+        builder.child("a").child("b").setProperty("foo", Lists.newArrayList(1L,2L,3L), Type.LONGS);
+        builder.child("a").child("b").setProperty("foo2", Lists.newArrayList("x", "y", "z"), Type.STRINGS);
+        builder.child("a").child("b").setProperty("foo3", Lists.newArrayList(true, false), Type.BOOLEANS);
+        builder.child("a").child(":c").setProperty("foo", "bar");
+
+        String jsop = NodeStateJsonUtils.toJson(builder.getNodeState(), false);
+        JSONObject json = (JSONObject) JSONValue.parseWithException(jsop);
+
+        assertTrue(json.containsKey("a"));
+        JSONObject a = (JSONObject) json.get("a");
+        JSONObject b = (JSONObject) a.get("b");
+        assertEquals(Lists.newArrayList(1L,2L,3L), b.get("foo"));
+        assertEquals(Lists.newArrayList("x", "y", "z"), b.get("foo2"));
+        assertEquals(Lists.newArrayList(true, false), b.get("foo3"));
+    }
+
+}
\ No newline at end of file
diff --git oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProvider.java oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProvider.java
new file mode 100644
index 0000000..1103ff0
--- /dev/null
+++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProvider.java
@@ -0,0 +1,176 @@
+/*
+ * 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.jackrabbit.oak.plugins.index.lucene;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfo;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.IndexInfo;
+import org.apache.jackrabbit.oak.plugins.index.IndexInfoProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.directory.DirectoryUtils;
+import org.apache.jackrabbit.oak.plugins.index.lucene.directory.IndexConsistencyChecker;
+import org.apache.jackrabbit.oak.plugins.index.lucene.writer.MultiplexersLucene;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.state.ReadOnlyBuilder;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.store.Directory;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class LuceneIndexInfoProvider implements IndexInfoProvider {
+
+    private final NodeStore nodeStore;
+
+    private final AsyncIndexInfoService asyncInfoService;
+
+    private final File workDir;
+
+    public LuceneIndexInfoProvider(NodeStore nodeStore, AsyncIndexInfoService asyncInfoService, File workDir) {
+        this.nodeStore = checkNotNull(nodeStore);
+        this.asyncInfoService = checkNotNull(asyncInfoService);
+        this.workDir = checkNotNull(workDir);
+    }
+
+    @Override
+    public String getType() {
+        return LuceneIndexConstants.TYPE_LUCENE;
+    }
+
+    @Override
+    public IndexInfo getInfo(String indexPath) throws IOException {
+        NodeState idxState = NodeStateUtils.getNode(nodeStore.getRoot(), indexPath);
+
+        checkArgument(LuceneIndexConstants.TYPE_LUCENE.equals(idxState.getString(IndexConstants.TYPE_PROPERTY_NAME)),
+                "Index definition at [%s] is not of type 'lucene'", indexPath);
+
+        LuceneIndexInfo info = new LuceneIndexInfo(indexPath);
+        computeSize(idxState, info);
+        computeAsyncIndexInfo(idxState, indexPath, info);
+        return info;
+    }
+
+    @Override
+    public boolean isValid(String indexPath) throws IOException {
+        IndexConsistencyChecker checker = new IndexConsistencyChecker(nodeStore.getRoot(), indexPath, workDir);
+        return checker.check(IndexConsistencyChecker.Level.BLOBS_ONLY).clean;
+    }
+
+    private void computeAsyncIndexInfo(NodeState idxState, String indexPath, LuceneIndexInfo info) {
+        String asyncName = getAsyncName(idxState, indexPath);
+        checkNotNull(asyncName, "No 'async' value for index definition " +
+                "at [%s]. Definition %s", indexPath, idxState);
+
+        AsyncIndexInfo asyncInfo = asyncInfoService.getInfo(asyncName);
+        checkNotNull(asyncInfo, "No async info found for name [%s] " +
+                "for index at [%s]", asyncName, indexPath);
+
+        info.indexedUptoTime = asyncInfo.getLastIndexedTo();
+        info.asyncName = asyncName;
+    }
+
+    static String getAsyncName(NodeState idxState, String indexPath) {
+        PropertyState async = idxState.getProperty(IndexConstants.ASYNC_PROPERTY_NAME);
+        if (async != null) {
+            Set<String> asyncNames = Sets.newHashSet(async.getValue(Type.STRINGS));
+            asyncNames.remove(IndexConstants.INDEXING_MODE_NRT);
+            asyncNames.remove(IndexConstants.INDEXING_MODE_SYNC);
+            checkArgument(!asyncNames.isEmpty(), "No valid async name found for " +
+                    "index [%s], definition %s", indexPath, idxState);
+            return Iterables.getOnlyElement(asyncNames);
+        }
+        return null;
+    }
+
+    private void computeSize(NodeState idxState, LuceneIndexInfo info) throws IOException {
+        IndexDefinition defn = IndexDefinition.newBuilder(nodeStore.getRoot(), idxState, info.indexPath).build();
+        for (String dirName : idxState.getChildNodeNames()) {
+            if (NodeStateUtils.isHidden(dirName) && MultiplexersLucene.isIndexDirName(dirName)) {
+                Directory dir = new OakDirectory(new ReadOnlyBuilder(idxState), dirName, defn, true);
+                try (DirectoryReader dirReader = DirectoryReader.open(dir)) {
+                    info.numEntries += dirReader.numDocs();
+                    info.size = DirectoryUtils.dirSize(dir);
+                }
+            }
+        }
+    }
+
+    private static class LuceneIndexInfo implements IndexInfo {
+        String indexPath;
+        String asyncName;
+        long numEntries;
+        long size;
+        long indexedUptoTime;
+
+        public LuceneIndexInfo(String indexPath) {
+            this.indexPath = indexPath;
+        }
+
+        @Override
+        public String getIndexPath() {
+            return indexPath;
+        }
+
+        @Override
+        public String getType() {
+            return LuceneIndexConstants.TYPE_LUCENE;
+        }
+
+        @Override
+        public String getAsyncName() {
+            return asyncName;
+        }
+
+        @Override
+        public long getLastUpdatedTime() {
+            return 0; //TODO To be computed
+        }
+
+        @Override
+        public long getIndexedUptoTime() {
+            return indexedUptoTime;
+        }
+
+        @Override
+        public long getEstimatedEntryCount() {
+            return numEntries;
+        }
+
+        @Override
+        public long getSizeInBytes() {
+            return size;
+        }
+
+        @Override
+        public boolean hasIndexDefinitionChangedWithoutReindexing() {
+            return false; //TODO To be computed
+        }
+    }
+}
diff --git oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java
index 15f5897..495186b 100644
--- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java
+++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java
@@ -51,7 +51,9 @@ import org.apache.jackrabbit.oak.cache.CacheStats;
 import org.apache.jackrabbit.oak.commons.PropertiesUtil;
 import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
 import org.apache.jackrabbit.oak.plugins.document.spi.JournalPropertyService;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexInfoProvider;
 import org.apache.jackrabbit.oak.plugins.index.IndexPathService;
 import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
 import org.apache.jackrabbit.oak.plugins.index.fulltext.PreExtractedTextProvider;
@@ -260,6 +262,9 @@ public class LuceneIndexProviderService {
     @Reference
     private IndexPathService indexPathService;
 
+    @Reference
+    private AsyncIndexInfoService asyncIndexInfoService;
+
     @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY,
         policyOption = ReferencePolicyOption.GREEDY,
         policy = ReferencePolicy.DYNAMIC
@@ -311,15 +316,20 @@ public class LuceneIndexProviderService {
         registerObserver(bundleContext, config);
         registerLocalIndexObserver(bundleContext, tracker, config);
         registerIndexEditor(bundleContext, tracker, config);
+        registerIndexInfoProvider(bundleContext);
 
         oakRegs.add(registerMBean(whiteboard,
                 LuceneIndexMBean.class,
-                new LuceneIndexMBeanImpl(indexProvider.getTracker(), nodeStore, indexPathService, new File(indexDir, "indexCheckDir")),
+                new LuceneIndexMBeanImpl(indexProvider.getTracker(), nodeStore, indexPathService, getIndexCheckDir()),
                 LuceneIndexMBean.TYPE,
                 "Lucene Index statistics"));
         registerGCMonitor(whiteboard, indexProvider.getTracker());
     }
 
+    private File getIndexCheckDir() {
+        return new File(checkNotNull(indexDir), "indexCheckDir");
+    }
+
     @Deactivate
     private void deactivate() throws InterruptedException, IOException {
         for (ServiceRegistration reg : regs) {
@@ -661,6 +671,11 @@ public class LuceneIndexProviderService {
         }
     }
 
+    private void registerIndexInfoProvider(BundleContext bundleContext) {
+        IndexInfoProvider infoProvider = new LuceneIndexInfoProvider(nodeStore, asyncIndexInfoService, getIndexCheckDir());
+        regs.add(bundleContext.registerService(IndexInfoProvider.class.getName(), infoProvider, null));
+    }
+
     protected void bindNodeAggregator(NodeAggregator aggregator) {
         this.nodeAggregator = aggregator;
         initialize();
diff --git oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java
new file mode 100644
index 0000000..986736c
--- /dev/null
+++ oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.jackrabbit.oak.plugins.index.lucene;
+
+import java.io.File;
+
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfo;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
+import org.apache.jackrabbit.oak.plugins.index.IndexInfo;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexDefinitionBuilder;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class LuceneIndexInfoProviderTest {
+
+    @Rule
+    public final TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
+    private NodeStore store = new MemoryNodeStore();
+    private AsyncIndexInfoService asyncService = mock(AsyncIndexInfoService.class);
+    private LuceneIndexInfoProvider provider;
+
+    @Before
+    public void setUp() {
+        provider = new LuceneIndexInfoProvider(store, asyncService, temporaryFolder.getRoot());
+    }
+
+    @Test
+    public void asyncName() throws Exception {
+        assertNull(LuceneIndexInfoProvider.getAsyncName(EMPTY_NODE, "/fooIndex"));
+
+        NodeBuilder builder = EMPTY_NODE.builder();
+        builder.setProperty("async", newArrayList("async2", "sync"), Type.STRINGS);
+        assertEquals("async2", LuceneIndexInfoProvider.getAsyncName(builder.getNodeState(), "/fooIndex"));
+
+        builder.setProperty("async", newArrayList("async3"), Type.STRINGS);
+        assertEquals("async3", LuceneIndexInfoProvider.getAsyncName(builder.getNodeState(), "/fooIndex"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void infoNonExisting() throws Exception {
+        provider.getInfo("/no/existing/path");
+    }
+
+    @Test
+    public void info() throws Exception {
+        IndexDefinitionBuilder defnBuilder = new IndexDefinitionBuilder();
+
+        NodeBuilder builder = store.getRoot().builder();
+        builder.child("oak:index").setChildNode("fooIndex", defnBuilder.build());
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        when(asyncService.getInfo("async"))
+                .thenReturn(new AsyncIndexInfo("async", 0,0, false, null));
+
+        IndexInfo info = provider.getInfo("/oak:index/fooIndex");
+
+        assertNotNull(info);
+    }
+
+}
\ No newline at end of file
diff --git oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java
index 4b3747a..c88a19f 100644
--- oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java
+++ oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java
@@ -39,6 +39,7 @@ import org.apache.jackrabbit.oak.plugins.blob.datastore.CachingFileDataStore;
 import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreBlobStore;
 import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreUtils;
 import org.apache.jackrabbit.oak.plugins.document.spi.JournalPropertyService;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.IndexPathService;
 import org.apache.jackrabbit.oak.plugins.index.fulltext.ExtractedText;
@@ -86,6 +87,7 @@ public class LuceneIndexProviderServiceTest {
         context.registerService(IndexAugmentorFactory.class, mock(IndexAugmentorFactory.class));
         context.registerService(NodeStore.class, new MemoryNodeStore());
         context.registerService(IndexPathService.class, mock(IndexPathService.class));
+        context.registerService(AsyncIndexInfoService.class, mock(AsyncIndexInfoService.class));
         MockOsgi.injectServices(service, context.bundleContext());
     }
 
