http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/common/params/ActionRegistryArgs.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/common/params/ActionRegistryArgs.java
 
b/slider-core/src/main/java/org/apache/slider/common/params/ActionRegistryArgs.java
index deae4eb..1e4aba5 100644
--- 
a/slider-core/src/main/java/org/apache/slider/common/params/ActionRegistryArgs.java
+++ 
b/slider-core/src/main/java/org/apache/slider/common/params/ActionRegistryArgs.java
@@ -47,8 +47,10 @@ public class ActionRegistryArgs extends AbstractActionArgs {
       + " ("
       + Arguments.ARG_LIST + "|"
       + Arguments.ARG_LISTCONF + "|"
+      + Arguments.ARG_LISTEXP + "|"
       + Arguments.ARG_LISTFILES + "|"
-      + Arguments.ARG_GETCONF + "> "
+      + Arguments.ARG_GETCONF + "|"
+      + Arguments.ARG_GETEXP + "> "
       + Arguments.ARG_NAME + " <name> "
       + " )"
       + "[" + Arguments.ARG_VERBOSE + "] "
@@ -56,6 +58,8 @@ public class ActionRegistryArgs extends AbstractActionArgs {
       + "[" + Arguments.ARG_OUTPUT + " <filename> ] "
       + "[" + Arguments.ARG_SERVICETYPE + " <servicetype> ] "
       + "[" + Arguments.ARG_FORMAT + " <xml|json|properties>] "
+      + System.getProperty("line.separator")
+      + "Arguments.ARG_GETEXP only supports " + Arguments.ARG_FORMAT + " json"
       ;
   public ActionRegistryArgs() {
   }
@@ -90,7 +94,14 @@ public class ActionRegistryArgs extends AbstractActionArgs {
       description = "get configuration")
   public String getConf;
 
-  @Parameter(names = {ARG_LISTFILES}, 
+  @Parameter(names = {ARG_LISTEXP},
+             description = "list exports")
+  public boolean listExports;
+  @Parameter(names = {ARG_GETEXP},
+             description = "get export")
+  public String getExport;
+
+  @Parameter(names = {ARG_LISTFILES},
       description = "list files")
   public String listFiles;
 
@@ -135,8 +146,8 @@ public class ActionRegistryArgs extends AbstractActionArgs {
     super.validate();
 
     //verify that at most one of the operations is set
-    int gets = s(getConf) + s(getFiles);
-    int lists = s(list) + s(listConf) + s(listFiles);
+    int gets = s(getConf) + s(getFiles) + s(getExport);
+    int lists = s(list) + s(listConf) + s(listFiles) + s(listExports);
     int set = lists + gets;
     if (set > 1) {
       throw new UsageException(USAGE);

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java 
b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
index ff064c8..2c536d9 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
@@ -52,6 +52,7 @@ public interface Arguments {
   String ARG_FORMAT = "--format";
   String ARG_FORCE = "--force";
   String ARG_GETCONF = "--getconf";
+  String ARG_GETEXP = "--getexp";
   String ARG_GETFILES = "--getfiles";
   String ARG_HELP = "--help";
   String ARG_ID = "--id";
@@ -60,6 +61,7 @@ public interface Arguments {
   String ARG_LEVEL = "--level";
   String ARG_LIST = "--list";
   String ARG_LISTCONF = "--listconf";
+  String ARG_LISTEXP = "--listexp";
   String ARG_LISTFILES = "--listfiles";
   String ARG_LIVE = "--live";
   String ARG_MANAGER = "--manager";

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/core/registry/docstore/ExportEntry.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/core/registry/docstore/ExportEntry.java
 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/ExportEntry.java
new file mode 100644
index 0000000..4bcf6c1
--- /dev/null
+++ 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/ExportEntry.java
@@ -0,0 +1,120 @@
+/*
+ * 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.slider.core.registry.docstore;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+/**
+ * JSON-serializable description of a published key-val configuration.
+ *
+ * The values themselves are not serialized in the external view; they have to 
be served up by the far end
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+public class ExportEntry {
+
+  /**
+   * The value of the export
+   */
+  private String value;
+  /**
+   * The container id of the container that is responsible for the export
+   */
+  private String containerId;
+  /**
+   * Tag associated with the container - its usually an identifier different 
than container id
+   * that allows a soft serial id to all containers of a component - e.g. 1, 
2, 3, ...
+   */
+  private String tag;
+  /**
+   * An export can be at the level of a component or an application
+   */
+  private String level;
+  /**
+   * The time when the export was updated
+   */
+  private String updatedTime;
+  /**
+   * The time when the export expires
+   */
+  private String validUntil;
+
+  public ExportEntry() {
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  public void setValue(String value) {
+    this.value = value;
+  }
+
+  public String getContainerId() {
+    return containerId;
+  }
+
+  public void setContainerId(String containerId) {
+    this.containerId = containerId;
+  }
+
+  public String getTag() {
+    return tag;
+  }
+
+  public void setTag(String tag) {
+    this.tag = tag;
+  }
+
+  public String getLevel() {
+    return level;
+  }
+
+  public void setLevel(String level) {
+    this.level = level;
+  }
+  public String getUpdatedTime() {
+    return updatedTime;
+  }
+
+  public void setUpdatedTime(String updatedTime) {
+    this.updatedTime = updatedTime;
+  }
+
+  public String getValidUntil() {
+    return validUntil;
+  }
+
+  public void setValidUntil(String validUntil) {
+    this.validUntil = validUntil;
+  }
+
+  @Override
+  public String toString() {
+    return new StringBuilder("ExportEntry{").
+        append("value='").append(value).append("',").
+        append("containerId='").append(containerId).append("',").
+        append("tag='").append(tag).append("',").
+        append("level='").append(level).append("'").
+        append("updatedTime='").append(updatedTime).append("'").
+        append("validUntil='").append(validUntil).append("'").
+        append(" }").toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExports.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExports.java
 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExports.java
new file mode 100644
index 0000000..d6d285c
--- /dev/null
+++ 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExports.java
@@ -0,0 +1,141 @@
+/*
+ * 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.slider.core.registry.docstore;
+
+import org.apache.commons.collections.IteratorUtils;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JSON-serializable description of a published key-val configuration.
+ *
+ * The values themselves are not serialized in the external view; they have to 
be served up by the far end
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+public class PublishedExports {
+
+  public String description;
+  public long updated;
+  public String updatedTime;
+  public Map<String, List<ExportEntry>> entries = new HashMap<String, 
List<ExportEntry>>();
+
+  public PublishedExports() {
+  }
+
+  /**
+   * build an empty published configuration
+   *
+   * @param description configuration description
+   */
+  public PublishedExports(String description) {
+    this.description = description;
+  }
+
+  /**
+   * Build a configuration from the entries
+   *
+   * @param description configuration description
+   * @param entries     entries to put
+   */
+  public PublishedExports(String description,
+                          Iterable<Map.Entry<String, List<ExportEntry>>> 
entries) {
+    this.description = description;
+    putValues(entries);
+  }
+
+  /**
+   * Is the configuration empty. This means either that it has not been given 
any values, or it is stripped down copy
+   * set down over the wire.
+   *
+   * @return
+   */
+  public boolean isEmpty() {
+    return entries.isEmpty();
+  }
+
+  public long getUpdated() {
+    return updated;
+  }
+
+  public void setUpdated(long updated) {
+    this.updated = updated;
+    this.updatedTime = new Date(updated).toString();
+  }
+
+  /**
+   * Set the values from an iterable (this includes a Hadoop Configuration and 
Java properties object). Any existing
+   * value set is discarded
+   *
+   * @param entries entries to put
+   */
+  public void putValues(Iterable<Map.Entry<String, List<ExportEntry>>> 
entries) {
+    this.entries = new HashMap<String, List<ExportEntry>>();
+    for (Map.Entry<String, List<ExportEntry>> entry : entries) {
+      this.entries.put(entry.getKey(), entry.getValue());
+    }
+  }
+
+  /**
+   * Return the values as json string
+   *
+   * @return
+   *
+   * @throws IOException
+   */
+  public String asJson() throws IOException {
+    ObjectMapper mapper = new ObjectMapper();
+    String json = mapper.writeValueAsString(entries);
+    return json;
+  }
+
+  /**
+   * This makes a copy without the nested content -so is suitable for 
returning as part of the list of a parent's
+   * values
+   *
+   * @return the copy
+   */
+  public PublishedExports shallowCopy() {
+    PublishedExports that = new PublishedExports();
+    that.description = this.description;
+    that.updated = this.updated;
+    that.updatedTime = this.updatedTime;
+    return that;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb =
+        new StringBuilder("PublishedConfiguration{");
+    sb.append("description='").append(description).append('\'');
+    sb.append(" entries = ").append(entries.size());
+    sb.append('}');
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsOutputter.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsOutputter.java
 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsOutputter.java
new file mode 100644
index 0000000..b21e717
--- /dev/null
+++ 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsOutputter.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.slider.core.registry.docstore;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/** Output a published configuration */
+public abstract class PublishedExportsOutputter {
+
+  protected final PublishedExports exports;
+
+  protected PublishedExportsOutputter(PublishedExports exports) {
+    this.exports = exports;
+  }
+
+  /**
+   * Create an outputter for the chosen format
+   *
+   * @param format  format enumeration
+   * @param exports owning config
+   * @return the outputter
+   */
+
+  public static PublishedExportsOutputter createOutputter(ConfigFormat format,
+                                                         PublishedExports 
exports) {
+    Preconditions.checkNotNull(exports);
+    switch (format) {
+      case JSON:
+        return new JsonOutputter(exports);
+      default:
+        throw new RuntimeException("Unsupported format :" + format);
+    }
+  }
+
+  public void save(File dest) throws IOException {
+    FileOutputStream out = null;
+    try {
+      out = new FileOutputStream(dest);
+      save(out);
+      out.close();
+    } finally {
+      org.apache.hadoop.io.IOUtils.closeStream(out);
+    }
+  }
+
+  /**
+   * Save the content. The default saves the asString() value to the output 
stream
+   *
+   * @param out output stream
+   * @throws IOException
+   */
+  public void save(OutputStream out) throws IOException {
+    IOUtils.write(asString(), out, Charsets.UTF_8);
+  }
+
+  /**
+   * Convert to a string
+   *
+   * @return
+   * @throws IOException
+   */
+  public abstract String asString() throws IOException;
+
+  public static class JsonOutputter extends PublishedExportsOutputter {
+
+    public JsonOutputter(PublishedExports exports) {
+      super(exports);
+    }
+
+    @Override
+    public void save(File dest) throws IOException {
+      FileUtils.writeStringToFile(dest, asString(), Charsets.UTF_8);
+    }
+
+    @Override
+    public String asString() throws IOException {
+      return exports.asJson();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsSet.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsSet.java
 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsSet.java
new file mode 100644
index 0000000..cdd35de
--- /dev/null
+++ 
b/slider-core/src/main/java/org/apache/slider/core/registry/docstore/PublishedExportsSet.java
@@ -0,0 +1,100 @@
+/*
+ * 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.slider.core.registry.docstore;
+
+import org.apache.slider.server.appmaster.web.rest.RestPaths;
+import org.apache.slider.server.services.utility.PatternValidator;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Represents a set of configurations for an application, component, etc.
+ * Json serialisable; accessors are synchronized
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+public class PublishedExportsSet {
+
+  private static final PatternValidator validator = new PatternValidator(
+      RestPaths.PUBLISHED_CONFIGURATION_REGEXP);
+  
+  public Map<String, PublishedExports> exports =
+      new HashMap<String, PublishedExports>();
+
+  public PublishedExportsSet() {
+  }
+
+  /**
+   * Put a name -it will be converted to lower case before insertion.
+   * Any existing entry will be overwritten (that includes an entry
+   * with a different case in the original name)
+   * @param name name of entry
+   * @param export published export
+   * @throws IllegalArgumentException if not a valid name
+   */
+  public void put(String name, PublishedExports export) {
+    String name1 = name.toLowerCase(Locale.ENGLISH);
+    validateName(name1);
+    exports.put(name1, export);
+  }
+
+  /**
+   * Validate the name -restricting it to the set defined in 
+   * {@link RestPaths#PUBLISHED_CONFIGURATION_REGEXP}
+   * @param name name to validate
+   * @throws IllegalArgumentException if not a valid name
+   */
+  public static void validateName(String name) {
+    validator.validate(name);
+    
+  }
+
+  public PublishedExports get(String name) {
+    return exports.get(name);
+  }
+  
+  public boolean contains(String name) {
+    return exports.containsKey(name);
+  }
+  
+  public int size() {
+    return exports.size();
+  }
+  
+  public Set<String> keys() {
+    TreeSet<String> keys = new TreeSet<String>();
+    keys.addAll(exports.keySet());
+    return keys;
+  }
+
+  public PublishedExportsSet shallowCopy() {
+    PublishedExportsSet that = new PublishedExportsSet();
+    for (Map.Entry<String, PublishedExports> entry :
+        exports.entrySet()) {
+      that.put(entry.getKey(), entry.getValue().shallowCopy());
+    }
+    return that;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/core/registry/info/CustomRegistryConstants.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/core/registry/info/CustomRegistryConstants.java
 
b/slider-core/src/main/java/org/apache/slider/core/registry/info/CustomRegistryConstants.java
index 65c122f..67b9feb 100644
--- 
a/slider-core/src/main/java/org/apache/slider/core/registry/info/CustomRegistryConstants.java
+++ 
b/slider-core/src/main/java/org/apache/slider/core/registry/info/CustomRegistryConstants.java
@@ -35,6 +35,9 @@ public class CustomRegistryConstants {
   public static final String PUBLISHER_CONFIGURATIONS_API =
       "org.apache.slider.publisher.configurations";
 
+  public static final String PUBLISHER_EXPORTS_API =
+      "org.apache.slider.publisher.exports";
+
   public static final String PUBLISHER_DOCUMENTS_API =
       "org.apache.slider.publisher.documents";
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java
 
b/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java
index 101efb2..a91f515 100644
--- 
a/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java
+++ 
b/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java
@@ -33,6 +33,8 @@ import org.apache.slider.common.tools.SliderUtils;
 import org.apache.slider.core.exceptions.ExceptionConverter;
 import org.apache.slider.core.registry.docstore.PublishedConfigSet;
 import org.apache.slider.core.registry.docstore.PublishedConfiguration;
+import org.apache.slider.core.registry.docstore.PublishedExports;
+import org.apache.slider.core.registry.docstore.PublishedExportsSet;
 import org.apache.slider.core.registry.info.CustomRegistryConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,6 +54,8 @@ public class RegistryRetriever {
 
   private final String externalConfigurationURL;
   private final String internalConfigurationURL;
+  private final String externalExportsURL;
+  private final String internalExportsURL;
   private static final Client jerseyClient;
   
   static {
@@ -63,9 +67,12 @@ public class RegistryRetriever {
     jerseyClient.setFollowRedirects(true);
   }
   
-  public RegistryRetriever(String externalConfigurationURL, String 
internalConfigurationURL) {
-    this.externalConfigurationURL = externalConfigurationURL; 
-    this.internalConfigurationURL = internalConfigurationURL; 
+  public RegistryRetriever(String externalConfigurationURL, String 
internalConfigurationURL,
+                           String externalExportsURL, String 
internalExportsURL) {
+    this.externalConfigurationURL = externalConfigurationURL;
+    this.internalConfigurationURL = internalConfigurationURL;
+    this.externalExportsURL = externalExportsURL;
+    this.internalExportsURL = internalExportsURL;
   }
 
   /**
@@ -99,6 +106,29 @@ public class RegistryRetriever {
       }
     }
     externalConfigurationURL = url;
+
+    internal = record.getInternalEndpoint(
+        CustomRegistryConstants.PUBLISHER_EXPORTS_API);
+    url = null;
+    if (internal != null) {
+      List<String> addresses = RegistryTypeUtils.retrieveAddressesUriType(
+          internal);
+      if (addresses != null && !addresses.isEmpty()) {
+        url = addresses.get(0);
+      }
+    }
+    internalExportsURL = url;
+    external = record.getExternalEndpoint(
+        CustomRegistryConstants.PUBLISHER_EXPORTS_API);
+    url = null;
+    if (external != null) {
+      List<String> addresses =
+          RegistryTypeUtils.retrieveAddressesUriType(external);
+      if (addresses != null && !addresses.isEmpty()) {
+        url = addresses.get(0);
+      }
+    }
+    externalExportsURL = url;
   }
 
   /**
@@ -138,6 +168,33 @@ public class RegistryRetriever {
     return confURL;
   }
 
+  protected String getExportURL(boolean external) throws FileNotFoundException 
{
+    String confURL = external ? externalExportsURL: internalExportsURL;
+    if (Strings.isStringEmpty(confURL)) {
+      throw new FileNotFoundException("No configuration URL");
+    }
+    return confURL;
+  }
+
+  /**
+   * Get the configurations of the registry
+   * @param external flag to indicate that it is the external entries to fetch
+   * @return the configuration sets
+   */
+  public PublishedExportsSet getExports(boolean external) throws
+      FileNotFoundException, IOException {
+
+    String exportsUrl = getExportURL(external);
+    try {
+      WebResource webResource = jsonResource(exportsUrl);
+      log.debug("GET {}", exportsUrl);
+      PublishedExportsSet exportSet = 
webResource.get(PublishedExportsSet.class);
+      return exportSet;
+    } catch (UniformInterfaceException e) {
+      throw ExceptionConverter.convertJerseyException(exportsUrl, e);
+    }
+  }
+
   private WebResource resource(String url) {
     WebResource resource = jerseyClient.resource(url);
     return resource;
@@ -174,7 +231,33 @@ public class RegistryRetriever {
       throw ExceptionConverter.convertJerseyException(confURL, e);
     }
   }
-  
+
+  /**
+   * Get a complete export, with all values
+   * @param exportSet
+   * @param name name of the configuration
+   * @param external flag to indicate that it is an external configuration
+   * @return the retrieved config
+   * @throws IOException IO problems
+   */
+  public PublishedExports retrieveExports(PublishedExportsSet exportSet,
+                                                      String name,
+                                                      boolean external) throws 
IOException {
+    if (!exportSet.contains(name)) {
+      throw new FileNotFoundException("Unknown export " + name);
+    }
+    String exportsURL = getExportURL(external);
+    exportsURL = SliderUtils.appendToURL(exportsURL, name);
+    try {
+      WebResource webResource = jsonResource(exportsURL);
+      PublishedExports publishedExports =
+          webResource.get(PublishedExports.class);
+      return publishedExports;
+    } catch (UniformInterfaceException e) {
+      throw ExceptionConverter.convertJerseyException(exportsURL, e);
+    }
+  }
+
   @Override
   public String toString() {
     return super.toString() 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
 
b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
index 44777c3..8b9b257 100644
--- 
a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
+++ 
b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
@@ -52,7 +52,9 @@ import org.apache.slider.core.exceptions.NoSuchNodeException;
 import org.apache.slider.core.exceptions.SliderException;
 import org.apache.slider.core.launch.CommandLineBuilder;
 import org.apache.slider.core.launch.ContainerLauncher;
+import org.apache.slider.core.registry.docstore.ExportEntry;
 import org.apache.slider.core.registry.docstore.PublishedConfiguration;
+import org.apache.slider.core.registry.docstore.PublishedExports;
 import org.apache.slider.core.registry.info.CustomRegistryConstants;
 import org.apache.slider.providers.AbstractProviderService;
 import org.apache.slider.providers.ProviderCore;
@@ -95,10 +97,13 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
@@ -106,6 +111,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -127,10 +133,15 @@ public class AgentProviderService extends 
AbstractProviderService implements
   private static final String CONTAINER_ID = "container_id";
   private static final String GLOBAL_CONFIG_TAG = "global";
   private static final String LOG_FOLDERS_TAG = "LogFolders";
+  private static final String HOST_FOLDER_FORMAT = "%s:%s";
+  private static final String CONTAINER_LOGS_TAG = "container_log_dirs";
+  private static final String CONTAINER_PWDS_TAG = "container_work_dirs";
+  private static final String COMPONENT_TAG = "component";
+  private static final String APPLICATION_TAG = "application";
   private static final String COMPONENT_DATA_TAG = "ComponentInstanceData";
   private static final String SHARED_PORT_TAG = "SHARED";
   private static final String PER_CONTAINER_TAG = "{PER_CONTAINER}";
-  private static final int MAX_LOG_ENTRIES = 20;
+  private static final int MAX_LOG_ENTRIES = 40;
   private static final int DEFAULT_HEARTBEAT_MONITOR_INTERVAL = 60 * 1000;
 
   private final Object syncLock = new Object();
@@ -149,16 +160,25 @@ public class AgentProviderService extends 
AbstractProviderService implements
       new ConcurrentHashMap<String, ComponentInstanceState>();
   private final Map<String, Map<String, String>> componentInstanceData =
       new ConcurrentHashMap<String, Map<String, String>>();
-  private final Map<String, Map<String, String>> exportGroups =
-      new ConcurrentHashMap<String, Map<String, String>>();
+  private final Map<String, Map<String, List<ExportEntry>>> exportGroups =
+      new ConcurrentHashMap<String, Map<String, List<ExportEntry>>>();
   private final Map<String, Map<String, String>> allocatedPorts =
       new ConcurrentHashMap<String, Map<String, String>>();
-  private final Map<String, String> workFolders =
-      Collections.synchronizedMap(new LinkedHashMap<String, 
String>(MAX_LOG_ENTRIES, 0.75f, false) {
+
+  private final Map<String, ExportEntry> logFolderExports =
+      Collections.synchronizedMap(new LinkedHashMap<String, 
ExportEntry>(MAX_LOG_ENTRIES, 0.75f, false) {
+        protected boolean removeEldestEntry(Map.Entry eldest) {
+          return size() > MAX_LOG_ENTRIES;
+        }
+      });
+  private final Map<String, ExportEntry> workFolderExports =
+      Collections.synchronizedMap(new LinkedHashMap<String, 
ExportEntry>(MAX_LOG_ENTRIES, 0.75f, false) {
         protected boolean removeEldestEntry(Map.Entry eldest) {
           return size() > MAX_LOG_ENTRIES;
         }
       });
+  private final Map<String, Set<String>> containerExportsMap =
+      new HashMap<String, Set<String>>();
 
   /**
    * Create an instance of AgentProviderService
@@ -491,7 +511,7 @@ public class AgentProviderService extends 
AbstractProviderService implements
 
       Map<String, String> folders = registration.getLogFolders();
       if (folders != null && !folders.isEmpty()) {
-        publishLogFolderPaths(folders, containerId, roleName, hostFqdn);
+        publishFolderPaths(folders, containerId, roleName, hostFqdn);
       }
     } else {
       response.setResponseStatus(RegistrationStatus.FAILED);
@@ -558,7 +578,7 @@ public class AgentProviderService extends 
AbstractProviderService implements
       log.info("Component operation. Status: {}", result);
 
       if (command == Command.INSTALL && report.getFolders() != null && 
report.getFolders().size() > 0) {
-        publishLogFolderPaths(report.getFolders(), containerId, roleName, 
heartBeat.getFqdn());
+        publishFolderPaths(report.getFolders(), containerId, roleName, 
heartBeat.getFqdn());
       }
     }
 
@@ -643,6 +663,7 @@ public class AgentProviderService extends 
AbstractProviderService implements
 
     // component specific publishes
     processAndPublishComponentSpecificData(ports, containerId, fqdn, roleName);
+    processAndPublishComponentSpecificExports(ports, containerId, fqdn, 
roleName);
 
     // and update registration entries
     if (instance != null) {
@@ -692,7 +713,7 @@ public class AgentProviderService extends 
AbstractProviderService implements
       throw new IOException(e);
     }
   }
-  
+
   @Override
   public void notifyContainerCompleted(ContainerId containerId) {
     if (containerId != null) {
@@ -714,6 +735,25 @@ public class AgentProviderService extends 
AbstractProviderService implements
           }
         }
       }
+
+      synchronized (this.containerExportsMap) {
+        Set<String> containerExportSets = 
containerExportsMap.get(containerIdStr);
+        if (containerExportSets != null) {
+          for (String containerExportStr : containerExportSets) {
+            String[] parts = containerExportStr.split(":");
+            Map<String, List<ExportEntry>> exportGroup = 
getCurrentExports(parts[0]);
+            List<ExportEntry> exports = exportGroup.get(parts[1]);
+            List<ExportEntry> exportToRemove = new ArrayList<ExportEntry>();
+            for (ExportEntry export : exports) {
+              if (containerIdStr.equals(export.getContainerId())) {
+                exportToRemove.add(export);
+              }
+            }
+            exports.removeAll(exportToRemove);
+          }
+          containerExportsMap.remove(containerIdStr);
+        }
+      }
     }
   }
 
@@ -749,6 +789,16 @@ public class AgentProviderService extends 
AbstractProviderService implements
   }
 
   @VisibleForTesting
+  protected Map<String, ExportEntry> getLogFolderExports() {
+    return logFolderExports;
+  }
+
+  @VisibleForTesting
+  protected Map<String, ExportEntry> getWorkFolderExports() {
+    return workFolderExports;
+  }
+
+  @VisibleForTesting
   protected Metainfo getMetainfo() {
     return this.metainfo;
   }
@@ -896,15 +946,59 @@ public class AgentProviderService extends 
AbstractProviderService implements
    * @param hostFqdn
    * @param roleName
    */
-  protected void publishLogFolderPaths(
+  protected void publishFolderPaths(
       Map<String, String> folders, String containerId, String roleName, String 
hostFqdn) {
-    for (Map.Entry<String, String> entry: folders.entrySet()) {
-      workFolders.put(String.format("%s->%s->%s->%s", roleName, hostFqdn, 
entry.getKey(), containerId), 
-        entry.getValue());
+    Date now = new Date();
+    for (Map.Entry<String, String> entry : folders.entrySet()) {
+      ExportEntry exportEntry = new ExportEntry();
+      exportEntry.setValue(String.format(HOST_FOLDER_FORMAT, hostFqdn, 
entry.getValue()));
+      exportEntry.setContainerId(containerId);
+      exportEntry.setLevel(COMPONENT_TAG);
+      exportEntry.setTag(roleName);
+      exportEntry.setUpdatedTime(now.toString());
+      if (entry.getKey().equals("AGENT_LOG_ROOT")) {
+        synchronized (logFolderExports) {
+          getLogFolderExports().put(containerId, exportEntry);
+        }
+      } else {
+        synchronized (workFolderExports) {
+          getWorkFolderExports().put(containerId, exportEntry);
+        }
+      }
+      log.info("Updating log and pwd folders for container {}", containerId);
     }
 
-    publishApplicationInstanceData(LOG_FOLDERS_TAG, LOG_FOLDERS_TAG,
-                                   (new HashMap<String, 
String>(this.workFolders)).entrySet());
+    PublishedExports exports = new PublishedExports(CONTAINER_LOGS_TAG);
+    exports.setUpdated(now.getTime());
+    synchronized (logFolderExports) {
+      updateExportsFromList(exports, getLogFolderExports());
+    }
+    getAmState().getPublishedExportsSet().put(CONTAINER_LOGS_TAG, exports);
+
+    exports = new PublishedExports(CONTAINER_PWDS_TAG);
+    exports.setUpdated(now.getTime());
+    synchronized (workFolderExports) {
+      updateExportsFromList(exports, getWorkFolderExports());
+    }
+    getAmState().getPublishedExportsSet().put(CONTAINER_PWDS_TAG, exports);
+  }
+
+  /**
+   * Update the export data from the map
+   * @param exports
+   * @param folderExports
+   */
+  private void updateExportsFromList(PublishedExports exports, Map<String, 
ExportEntry> folderExports) {
+    Map<String, List<ExportEntry>> perComponentList = new HashMap<String, 
List<ExportEntry>>();
+    for(Map.Entry<String, ExportEntry> logEntry : folderExports.entrySet())
+    {
+      String componentName = logEntry.getValue().getTag();
+      if(!perComponentList.containsKey(componentName)) {
+        perComponentList.put(componentName, new ArrayList<ExportEntry>());
+      }
+      perComponentList.get(componentName).add(logEntry.getValue());
+    }
+    exports.putValues(perComponentList.entrySet());
   }
 
 
@@ -949,13 +1043,12 @@ public class AgentProviderService extends 
AbstractProviderService implements
             }
           }
 
-          List<ExportGroup> exportGroups = application.getExportGroups();
-          boolean hasExportGroups = exportGroups != null && 
!exportGroups.isEmpty();
+          List<ExportGroup> appExportGroups = application.getExportGroups();
+          boolean hasExportGroups = appExportGroups != null && 
!appExportGroups.isEmpty();
 
           Set<String> appExports = new HashSet();
           String appExportsStr = 
getApplicationComponent(roleName).getAppExports();
-          boolean hasNoAppExports = appExportsStr == null || 
appExportsStr.isEmpty();
-          if (!hasNoAppExports) {
+          if (SliderUtils.isSet(appExportsStr)) {
             for (String appExport : appExportsStr.split(",")) {
               if (appExport.trim().length() > 0) {
                 appExports.add(appExport.trim());
@@ -983,11 +1076,12 @@ public class AgentProviderService extends 
AbstractProviderService implements
             }
 
             Set<String> modifiedGroups = new HashSet<String>();
-            for (ExportGroup exportGroup : exportGroups) {
+            for (ExportGroup exportGroup : appExportGroups) {
               List<Export> exports = exportGroup.getExports();
               if (exports != null && !exports.isEmpty()) {
                 String exportGroupName = exportGroup.getName();
-                Map<String, String> map = getCurrentExports(exportGroupName);
+                ConcurrentHashMap<String, List<ExportEntry>> map =
+                    (ConcurrentHashMap<String, 
List<ExportEntry>>)getCurrentExports(exportGroupName);
                 for (Export export : exports) {
                   if (canBeExported(exportGroupName, export.getName(), 
appExports)) {
                     String value = export.getValue();
@@ -997,7 +1091,12 @@ public class AgentProviderService extends 
AbstractProviderService implements
                         value = value.replace(token, replaceTokens.get(token));
                       }
                     }
-                    map.put(export.getName(), value);
+                    ExportEntry entry = new ExportEntry();
+                    entry.setLevel(APPLICATION_TAG);
+                    entry.setValue(value);
+                    entry.setUpdatedTime(new Date().toString());
+                    // over-write, app exports are singletons
+                    map.put(export.getName(), new 
ArrayList(Arrays.asList(entry)));
                     log.info("Preparing to publish. Key {} and Value {}", 
export.getName(), value);
                   }
                 }
@@ -1019,11 +1118,11 @@ public class AgentProviderService extends 
AbstractProviderService implements
     return appExports.contains(String.format("%s-%s", exportGroupName, name));
   }
 
-  protected Map<String, String> getCurrentExports(String groupName) {
+  protected Map<String, List<ExportEntry>> getCurrentExports(String groupName) 
{
     if (!this.exportGroups.containsKey(groupName)) {
       synchronized (this.exportGroups) {
         if (!this.exportGroups.containsKey(groupName)) {
-          this.exportGroups.put(groupName, new ConcurrentHashMap<String, 
String>());
+          this.exportGroups.put(groupName, new ConcurrentHashMap<String, 
List<ExportEntry>>());
         }
       }
     }
@@ -1032,10 +1131,24 @@ public class AgentProviderService extends 
AbstractProviderService implements
   }
 
   private void publishModifiedExportGroups(Set<String> modifiedGroups) {
-    synchronized (this.exportGroups) {
-      for (String groupName : modifiedGroups) {
-        publishApplicationInstanceData(groupName, groupName, 
this.exportGroups.get(groupName).entrySet());
+    for (String groupName : modifiedGroups) {
+      Map<String, List<ExportEntry>> entries = 
this.exportGroups.get(groupName);
+
+      // Publish in old format for the time being
+      Map<String, String> simpleEntries = new HashMap<String, String>();
+      for (Map.Entry<String, List<ExportEntry>> entry : entries.entrySet()) {
+        List<ExportEntry> exports = entry.getValue();
+        if(exports != null && exports.size() > 0) {
+          // there is no support for multiple exports per name - so extract 
only the first one
+          simpleEntries.put(entry.getKey(), 
entry.getValue().get(0).getValue());
+        }
       }
+      publishApplicationInstanceData(groupName, groupName, 
simpleEntries.entrySet());
+
+      PublishedExports exports = new PublishedExports(groupName);
+      exports.setUpdated(new Date().getTime());
+      exports.putValues(entries.entrySet());
+      getAmState().getPublishedExportsSet().put(groupName, exports);
     }
   }
 
@@ -1090,14 +1203,102 @@ public class AgentProviderService extends 
AbstractProviderService implements
     }
   }
 
+  /** Publish component instance specific data if the component demands it */
+  protected void processAndPublishComponentSpecificExports(Map<String, String> 
ports,
+                                                           String containerId,
+                                                           String hostFqdn,
+                                                           String roleName) {
+    String portVarFormat = "${site.%s}";
+    String hostNamePattern = "${" + roleName + "_HOST}";
+
+    List<ExportGroup> appExportGroups = 
getMetainfo().getApplication().getExportGroups();
+    Component component = getMetainfo().getApplicationComponent(roleName);
+    if (component != null && SliderUtils.isSet(component.getCompExports())
+        && appExportGroups != null && appExportGroups.size() > 0) {
+
+      Set<String> compExports = new HashSet();
+      String compExportsStr = component.getCompExports();
+      for (String appExport : compExportsStr.split(",")) {
+        if (appExport.trim().length() > 0) {
+          compExports.add(appExport.trim());
+        }
+      }
+
+      Date now = new Date();
+      Set<String> modifiedGroups = new HashSet<String>();
+      for (ExportGroup exportGroup : appExportGroups) {
+        List<Export> exports = exportGroup.getExports();
+        if (exports != null && !exports.isEmpty()) {
+          String exportGroupName = exportGroup.getName();
+          ConcurrentHashMap<String, List<ExportEntry>> map =
+              (ConcurrentHashMap<String, List<ExportEntry>>) 
getCurrentExports(exportGroupName);
+          for (Export export : exports) {
+            if (canBeExported(exportGroupName, export.getName(), compExports)) 
{
+              log.info("Attempting to publish {} of group {} for component 
type {}",
+                       export.getName(), exportGroupName, roleName);
+              String templateToExport = export.getValue();
+              for (String portName : ports.keySet()) {
+                boolean publishData = false;
+                String portValPattern = String.format(portVarFormat, portName);
+                if (templateToExport.contains(portValPattern)) {
+                  templateToExport = templateToExport.replace(portValPattern, 
ports.get(portName));
+                  publishData = true;
+                }
+                if (templateToExport.contains(hostNamePattern)) {
+                  templateToExport = templateToExport.replace(hostNamePattern, 
hostFqdn);
+                  publishData = true;
+                }
+                if (publishData) {
+                  ExportEntry entryToAdd = new ExportEntry();
+                  entryToAdd.setLevel(COMPONENT_TAG);
+                  entryToAdd.setValue(templateToExport);
+                  entryToAdd.setUpdatedTime(now.toString());
+                  entryToAdd.setContainerId(containerId);
+
+                  List<ExportEntry> existingList =
+                      map.putIfAbsent(export.getName(), new 
CopyOnWriteArrayList(Arrays.asList(entryToAdd)));
+
+                  // in-place edit, no lock needed
+                  if (existingList != null) {
+                    boolean updatedInPlace = false;
+                    for (ExportEntry entry : existingList) {
+                      if 
(containerId.equalsIgnoreCase(entry.getContainerId())) {
+                        entryToAdd.setValue(templateToExport);
+                        entryToAdd.setUpdatedTime(now.toString());
+                        updatedInPlace = true;
+                      }
+                    }
+                    if (!updatedInPlace) {
+                      existingList.add(entryToAdd);
+                    }
+                  }
+
+                  log.info("Publishing {} for name {} and container {}",
+                           templateToExport, export.getName(), containerId);
+                  modifiedGroups.add(exportGroupName);
+                  synchronized (containerExportsMap) {
+                    if (!containerExportsMap.containsKey(containerId)) {
+                      containerExportsMap.put(containerId, new 
HashSet<String>());
+                    }
+                    Set<String> containerExportMaps = 
containerExportsMap.get(containerId);
+                    containerExportMaps.add(String.format("%s:%s", 
exportGroupName, export.getName()));
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      publishModifiedExportGroups(modifiedGroups);
+    }
+  }
+
   private void publishComponentInstanceData() {
     Map<String, String> dataToPublish = new HashMap<String, String>();
-    synchronized (this.componentInstanceData) {
-      for (String container : getComponentInstanceData().keySet()) {
-        for (String prop : getComponentInstanceData().get(container).keySet()) 
{
-          dataToPublish.put(
-              container + "." + prop, 
getComponentInstanceData().get(container).get(prop));
-        }
+    for (String container : getComponentInstanceData().keySet()) {
+      for (String prop : getComponentInstanceData().get(container).keySet()) {
+        dataToPublish.put(
+            container + "." + prop, 
getComponentInstanceData().get(container).get(prop));
       }
     }
     publishApplicationInstanceData(COMPONENT_DATA_TAG, COMPONENT_DATA_TAG, 
dataToPublish.entrySet());
@@ -1580,5 +1781,4 @@ public class AgentProviderService extends 
AbstractProviderService implements
                   "");
     }
   }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
 
b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
index 9f3dd0f..418868c 100644
--- 
a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
+++ 
b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
@@ -34,6 +34,7 @@ public class Component {
   String maxInstanceCount;
   String autoStartOnFailure;
   String appExports;
+  String compExports;
   CommandScript commandScript;
   List<ComponentExport> componentExports;
 
@@ -82,6 +83,14 @@ public class Component {
     this.appExports = appExports;
   }
 
+  public String getCompExports() {
+    return compExports;
+  }
+
+  public void setCompExports(String compExports) {
+    this.compExports = compExports;
+  }
+
   public String getMinInstanceCount() {
     return minInstanceCount;
   }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
 
b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
index c92c265..1d8403f 100644
--- 
a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
+++ 
b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/MetainfoParser.java
@@ -61,6 +61,7 @@ public class MetainfoParser {
     digester.addBeanPropertySetter("*/component/maxInstanceCount");
     digester.addBeanPropertySetter("*/component/autoStartOnFailure");
     digester.addBeanPropertySetter("*/component/appExports");
+    digester.addBeanPropertySetter("*/component/compExports");
     digester.addObjectCreate("*/componentExport", ComponentExport.class);
     digester.addBeanPropertySetter("*/componentExport/name");
     digester.addBeanPropertySetter("*/componentExport/value");

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
 
b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
index 601c3f9..afe6428 100644
--- 
a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
+++ 
b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
@@ -146,6 +146,8 @@ public class SliderAMProviderService extends 
AbstractProviderService implements
 
       String configurationsURL = SliderUtils.appendToURL(
           publisherURL.toExternalForm(), RestPaths.SLIDER_CONFIGSET);
+      String exportsURL = SliderUtils.appendToURL(
+          publisherURL.toExternalForm(), RestPaths.SLIDER_EXPORTS);
 
       serviceRecord.addExternalEndpoint(
           RegistryTypeUtils.webEndpoint(
@@ -166,6 +168,10 @@ public class SliderAMProviderService extends 
AbstractProviderService implements
           RegistryTypeUtils.restEndpoint(
               CustomRegistryConstants.PUBLISHER_CONFIGURATIONS_API,
               new URI(configurationsURL)));
+      serviceRecord.addExternalEndpoint(
+          RegistryTypeUtils.restEndpoint(
+              CustomRegistryConstants.PUBLISHER_EXPORTS_API,
+              new URI(exportsURL)));
 
     } catch (URISyntaxException e) {
       throw new IOException(e);

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
index a0871ae..9c5da12 100644
--- 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
+++ 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
@@ -26,6 +26,7 @@ import org.apache.slider.core.conf.AggregateConf;
 import org.apache.slider.core.conf.ConfTreeOperations;
 import org.apache.slider.core.exceptions.NoSuchNodeException;
 import org.apache.slider.core.registry.docstore.PublishedConfigSet;
+import org.apache.slider.core.registry.docstore.PublishedExportsSet;
 import org.apache.slider.server.appmaster.web.rest.RestPaths;
 import org.apache.slider.server.services.utility.PatternValidator;
 
@@ -40,6 +41,7 @@ public class ProviderAppState implements 
StateAccessForProviders {
 
   private final Map<String, PublishedConfigSet> publishedConfigSets =
       new ConcurrentHashMap<String, PublishedConfigSet>(5);
+  private final PublishedExportsSet publishedExportsSets = new 
PublishedExportsSet();
   private static final PatternValidator validator = new PatternValidator(
       RestPaths.PUBLISHED_CONFIGURATION_SET_REGEXP);
   private String applicationName;
@@ -66,6 +68,11 @@ public class ProviderAppState implements 
StateAccessForProviders {
   }
 
   @Override
+  public PublishedExportsSet getPublishedExportsSet() {
+    return publishedExportsSets;
+  }
+
+  @Override
   public PublishedConfigSet getPublishedConfigSet(String name) {
     return publishedConfigSets.get(name);
   }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
index 1714f75..b907b06 100644
--- 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
+++ 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
@@ -26,6 +26,7 @@ import org.apache.slider.core.conf.AggregateConf;
 import org.apache.slider.core.conf.ConfTreeOperations;
 import org.apache.slider.core.exceptions.NoSuchNodeException;
 import org.apache.slider.core.registry.docstore.PublishedConfigSet;
+import org.apache.slider.core.registry.docstore.PublishedExportsSet;
 
 import java.util.Collection;
 import java.util.List;
@@ -51,6 +52,12 @@ public interface StateAccessForProviders {
   PublishedConfigSet getPublishedSliderConfigurations();
 
   /**
+   * Get the published exports set
+   * @return
+   */
+  PublishedExportsSet getPublishedExportsSet();
+
+  /**
    * Get a named published config set
    * @param name name to look up
    * @return the instance or null

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
index 93601ad..94f1e4c 100644
--- 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
+++ 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
@@ -61,6 +61,7 @@ public class RestPaths {
       = "[a-z0-9][a-z0-9_.\\+-]*";
 
   public static final String SLIDER_CONFIGSET = "slider";
+  public static final String SLIDER_EXPORTS = "exports";
 
   public static final String SLIDER_CLASSPATH = "classpath";
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/publisher/PublisherResource.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/publisher/PublisherResource.java
 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/publisher/PublisherResource.java
index 5d8b657..e47bbb9 100644
--- 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/publisher/PublisherResource.java
+++ 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/publisher/PublisherResource.java
@@ -23,6 +23,8 @@ import org.apache.slider.core.registry.docstore.ConfigFormat;
 import org.apache.slider.core.registry.docstore.PublishedConfigSet;
 import org.apache.slider.core.registry.docstore.PublishedConfiguration;
 import 
org.apache.slider.core.registry.docstore.PublishedConfigurationOutputter;
+import org.apache.slider.core.registry.docstore.PublishedExports;
+import org.apache.slider.core.registry.docstore.PublishedExportsSet;
 import org.apache.slider.core.registry.docstore.UriMap;
 import org.apache.slider.server.appmaster.state.StateAccessForProviders;
 import org.apache.slider.server.appmaster.web.WebAppApi;
@@ -56,7 +58,10 @@ public class PublisherResource {
   protected static final Logger log =
       LoggerFactory.getLogger(PublisherResource.class);
   private final WebAppApi slider;
-  public static final String SET_NAME = 
+  public static final String EXPORTS_NAME = "exports";
+  public static final String EXPORTS_RESOURCES_PATH = "/" + EXPORTS_NAME;
+  public static final String EXPORT_RESOURCE_PATH = EXPORTS_RESOURCES_PATH + 
"/{exportname}" ;
+  public static final String SET_NAME =
       "{setname: " + PUBLISHED_CONFIGURATION_SET_REGEXP + "}";
   private static final String CONFIG =
       SET_NAME + "/{config: " + PUBLISHED_CONFIGURATION_REGEXP + "}";
@@ -101,7 +106,9 @@ public class PublisherResource {
     UriMap uriMap = new UriMap();
     for (String name : appState.listConfigSets()) {
       uriMap.put(name, baseURL + name);
+      log.info("Tick tack {} and {}", name, baseURL);
     }
+    uriMap.put(EXPORTS_NAME, baseURL + EXPORTS_NAME);
     return uriMap;
   }
 
@@ -114,6 +121,26 @@ public class PublisherResource {
   }
 
   @GET
+  @Path(EXPORTS_RESOURCES_PATH)
+  @Produces({MediaType.APPLICATION_JSON})
+  public PublishedExportsSet gePublishedExports() {
+
+    PublishedExportsSet set = appState.getPublishedExportsSet();
+    return set.shallowCopy();
+  }
+
+  @GET
+  @Path(EXPORT_RESOURCE_PATH)
+  @Produces({MediaType.APPLICATION_JSON})
+  public PublishedExports getAMExports2(@PathParam("exportname") String 
exportname,
+                              @Context UriInfo uriInfo,
+                              @Context HttpServletResponse res) {
+    init(res, uriInfo);
+    PublishedExportsSet set = appState.getPublishedExportsSet();
+    return set.get(exportname);
+  }
+
+  @GET
   @Path("/"+ SET_NAME)
   @Produces({MediaType.APPLICATION_JSON})
   public PublishedConfigSet getPublishedConfiguration(
@@ -129,7 +156,7 @@ public class PublisherResource {
   }
 
   private void logRequest(UriInfo uriInfo) {
-    log.debug(uriInfo.getRequestUri().toString());
+    log.info(uriInfo.getRequestUri().toString());
   }
 
   @GET

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy 
b/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
index d1f8a8f..7d596d6 100644
--- 
a/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
+++ 
b/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
@@ -24,8 +24,10 @@ import org.apache.hadoop.conf.Configuration
 import org.apache.slider.common.params.ActionRegistryArgs
 import org.apache.slider.common.params.Arguments
 import org.apache.slider.common.params.SliderActions
+import org.apache.slider.core.exceptions.BadCommandArgumentsException
 import org.apache.slider.core.exceptions.ErrorStrings
 import org.apache.slider.core.exceptions.UsageException
+import org.apache.slider.core.main.ServiceLauncher
 import org.apache.slider.core.main.ServiceLauncherBaseTest
 import org.junit.Test
 
@@ -88,4 +90,45 @@ class TestClientBadArgs extends ServiceLauncherBaseTest {
     log.info(exception.toString())
   }
 
+  @Test
+  public void testRegistryExportBadUsage1() throws Throwable {
+    def exception = launchExpectingException(SliderClient,
+        new Configuration(),
+        "Expected a value after parameter --getexp",
+        [SliderActions.ACTION_REGISTRY,
+            Arguments.ARG_NAME,
+            "cl1",
+            Arguments.ARG_GETEXP])
+    assert exception instanceof BadCommandArgumentsException
+    log.info(exception.toString())
+  }
+
+  @Test
+  public void testRegistryExportBadUsage2() throws Throwable {
+    def exception = launchExpectingException(SliderClient,
+        new Configuration(),
+        "Expected a value after parameter --getexp",
+        [SliderActions.ACTION_REGISTRY,
+            Arguments.ARG_NAME,
+            "cl1",
+            Arguments.ARG_LISTEXP,
+        Arguments.ARG_GETEXP])
+    assert exception instanceof BadCommandArgumentsException
+    log.info(exception.toString())
+  }
+
+  @Test
+  public void testRegistryExportBadUsage3() throws Throwable {
+    def exception = launchExpectingException(SliderClient,
+        new Configuration(),
+        "Usage: registry",
+        [SliderActions.ACTION_REGISTRY,
+            Arguments.ARG_NAME,
+            "cl1",
+            Arguments.ARG_LISTEXP,
+            Arguments.ARG_GETEXP,
+            "export1"])
+    assert exception instanceof UsageException
+    log.info(exception.toString())
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
 
b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
index 7eff45a..a20e7a9 100644
--- 
a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
+++ 
b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
@@ -25,6 +25,7 @@ import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.registry.client.api.RegistryConstants;
 import org.apache.hadoop.registry.client.api.RegistryOperations;
 import org.apache.hadoop.registry.client.types.ServiceRecord;
+import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
 import org.apache.hadoop.yarn.api.records.Container;
 import org.apache.hadoop.yarn.api.records.ContainerId;
 import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
@@ -45,6 +46,9 @@ import org.apache.slider.core.conf.ConfTreeOperations;
 import org.apache.slider.core.conf.MapOperations;
 import org.apache.slider.core.exceptions.SliderException;
 import org.apache.slider.core.launch.ContainerLauncher;
+import org.apache.slider.core.registry.docstore.ExportEntry;
+import org.apache.slider.core.registry.docstore.PublishedExports;
+import org.apache.slider.core.registry.docstore.PublishedExportsSet;
 import org.apache.slider.providers.ProviderRole;
 import org.apache.slider.providers.agent.application.metadata.Application;
 import org.apache.slider.providers.agent.application.metadata.CommandOrder;
@@ -94,6 +98,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createNiceMock;
@@ -136,6 +141,10 @@ public class TestAgentProviderService {
                                                + "              
<name>Master_Status</name>\n"
                                                + "              
<value>http://${HBASE_MASTER_HOST}:${site.hbase-site.hbase.master.info.port}/master-status</value>\n"
                                                + "            </export>\n"
+                                               + "            <export>\n"
+                                               + "              
<name>Comp_Endpoint</name>\n"
+                                               + "              
<value>http://${HBASE_REGIONSERVER_HOST}:${site.global.listen_port}</value>\n"
+                                               + "            </export>\n"
                                                + "          </exports>\n"
                                                + "        </exportGroup>\n"
                                                + "      </exportGroups>\n"
@@ -165,6 +174,7 @@ public class TestAgentProviderService {
                                                + "          
<publishConfig>true</publishConfig>\n"
                                                + "          
<autoStartOnFailure>true</autoStartOnFailure>\n"
                                                + "          
<appExports>QuickLinks-JMX_Endpoint,QuickLinks-Master_Status</appExports>\n"
+                                               + "          
<compExports>QuickLinks-Comp_Endpoint</compExports>\n"
                                                + "          
<minInstanceCount>1</minInstanceCount>\n"
                                                + "          
<maxInstanceCount>2</maxInstanceCount>\n"
                                                + "          <commandScript>\n"
@@ -182,6 +192,7 @@ public class TestAgentProviderService {
                                                + "            
<script>scripts/hbase_regionserver.py</script>\n"
                                                + "            
<scriptType>PYTHON</scriptType>\n"
                                                + "          </commandScript>\n"
+                                               + "          
<compExports>QuickLinks-Comp_Endpoint</compExports>\n"
                                                + "          
<componentExports>\n"
                                                + "            
<componentExport>\n"
                                                + "              
<name>PropertyA</name>\n"
@@ -322,10 +333,10 @@ public class TestAgentProviderService {
         anyMap()
     );
 
-    doNothing().when(mockAps).publishLogFolderPaths(anyMap(),
-                                                    anyString(),
-                                                    anyString(),
-                                                    anyString()
+    doNothing().when(mockAps).publishFolderPaths(anyMap(),
+                                                 anyString(),
+                                                 anyString(),
+                                                 anyString()
     );
     expect(access.isApplicationLive()).andReturn(true).anyTimes();
     ClusterDescription desc = new ClusterDescription();
@@ -378,7 +389,7 @@ public class TestAgentProviderService {
         anyMap()
     );
 
-    Mockito.verify(mockAps, Mockito.times(1)).publishLogFolderPaths(
+    Mockito.verify(mockAps, Mockito.times(1)).publishFolderPaths(
         anyMap(),
         anyString(),
         anyString(),
@@ -694,6 +705,92 @@ public class TestAgentProviderService {
     }
   }
 
+
+  @Test
+  public void testComponentSpecificPublishes2() throws Exception {
+    InputStream metainfo_1 = new 
ByteArrayInputStream(metainfo_1_str.getBytes());
+    Metainfo metainfo = new MetainfoParser().parse(metainfo_1);
+    AgentProviderService aps = createAgentProviderService(new Configuration());
+    AgentProviderService mockAps = Mockito.spy(aps);
+    doNothing().when(mockAps).publishApplicationInstanceData(anyString(), 
anyString(), anyCollection());
+    doReturn(metainfo).when(mockAps).getMetainfo();
+    StateAccessForProviders access = 
createNiceMock(StateAccessForProviders.class);
+    doReturn(access).when(mockAps).getAmState();
+    PublishedExportsSet pubExpSet = new PublishedExportsSet();
+    expect(access.getPublishedExportsSet()).andReturn(pubExpSet).anyTimes();
+    replay(access);
+
+    Map<String, String> ports = new HashMap<String, String>();
+    ports.put("global.listen_port", "10010");
+    mockAps.processAndPublishComponentSpecificExports(ports,
+                                                      "mockcontainer_1",
+                                                      "host1",
+                                                      "HBASE_REGIONSERVER");
+    ArgumentCaptor<Collection> entriesCaptor = ArgumentCaptor.
+        forClass(Collection.class);
+    ArgumentCaptor<String> publishNameCaptor = ArgumentCaptor.
+        forClass(String.class);
+    Mockito.verify(mockAps, Mockito.times(1)).publishApplicationInstanceData(
+        anyString(),
+        publishNameCaptor.capture(),
+        entriesCaptor.capture());
+
+    PublishedExports pubExports = pubExpSet.get("QuickLinks".toLowerCase());
+    Assert.assertEquals(1, pubExports.entries.size());
+    Assert.assertEquals("QuickLinks", pubExports.description);
+    List<ExportEntry> expEntries = pubExports.entries.get("Comp_Endpoint");
+    Assert.assertEquals(1, expEntries.size());
+    Assert.assertEquals("mockcontainer_1", expEntries.get(0).getContainerId());
+    Assert.assertEquals("component", expEntries.get(0).getLevel());
+    Assert.assertEquals(null, expEntries.get(0).getTag());
+    Assert.assertEquals("http://host1:10010";, expEntries.get(0).getValue());
+    Assert.assertNotNull(expEntries.get(0).getUpdatedTime());
+    Assert.assertNull(expEntries.get(0).getValidUntil());
+
+    assert entriesCaptor.getAllValues().size() == 1;
+    for (Collection coll : entriesCaptor.getAllValues()) {
+      Set<Map.Entry<String, String>> entrySet = (Set<Map.Entry<String, 
String>>) coll;
+      for (Map.Entry entry : entrySet) {
+        log.info("{}:{}", entry.getKey(), entry.getValue().toString());
+        if (entry.getKey().equals("Comp_Endpoint")) {
+          assert entry.getValue().toString().equals("http://host1:10010";);
+        }
+      }
+    }
+    assert publishNameCaptor.getAllValues().size() == 1;
+    for (String coll : publishNameCaptor.getAllValues()) {
+      assert coll.equals("QuickLinks");
+    }
+
+    mockAps.notifyContainerCompleted(new MockContainerId(1));
+    pubExports = pubExpSet.get("QuickLinks".toLowerCase());
+    Assert.assertEquals(1, pubExports.entries.size());
+    Assert.assertEquals("QuickLinks", pubExports.description);
+    expEntries = pubExports.entries.get("Comp_Endpoint");
+    Assert.assertEquals(0, expEntries.size());
+
+    mockAps.notifyContainerCompleted(new MockContainerId(1));
+    mockAps.notifyContainerCompleted(new MockContainerId(2));
+
+    mockAps.processAndPublishComponentSpecificExports(ports,
+                                                      "mockcontainer_1",
+                                                      "host1",
+                                                      "HBASE_REGIONSERVER");
+    mockAps.processAndPublishComponentSpecificExports(ports,
+                                                      "mockcontainer_2",
+                                                      "host1",
+                                                      "HBASE_REGIONSERVER");
+    pubExports = pubExpSet.get("QuickLinks".toLowerCase());
+    Assert.assertEquals(1, pubExports.entries.size());
+    Assert.assertEquals("QuickLinks", pubExports.description);
+    expEntries = pubExports.entries.get("Comp_Endpoint");
+    Assert.assertEquals(2, expEntries.size());
+
+    mockAps.notifyContainerCompleted(new MockContainerId(2));
+    expEntries = pubExports.entries.get("Comp_Endpoint");
+    Assert.assertEquals(1, expEntries.size());
+  }
+
   @Test
   public void testProcessConfig() throws Exception {
     InputStream metainfo_1 = new 
ByteArrayInputStream(metainfo_1_str.getBytes());
@@ -728,6 +825,11 @@ public class TestAgentProviderService {
     doNothing().when(mockAps).publishApplicationInstanceData(anyString(), 
anyString(), anyCollection());
     doReturn(metainfo).when(mockAps).getMetainfo();
     doReturn(roleClusterNodeMap).when(mockAps).getRoleClusterNodeMapping();
+    StateAccessForProviders access = 
createNiceMock(StateAccessForProviders.class);
+    doReturn(access).when(mockAps).getAmState();
+    PublishedExportsSet pubExpSet = new PublishedExportsSet();
+    expect(access.getPublishedExportsSet()).andReturn(pubExpSet).anyTimes();
+    replay(access);
 
     mockAps.publishConfigAndExportGroups(hb, componentStatus, "HBASE_MASTER");
     Assert.assertTrue(componentStatus.getConfigReported());
@@ -748,15 +850,30 @@ public class TestAgentProviderService {
       }
     }
 
-    Map<String, String> exports = mockAps.getCurrentExports("QuickLinks");
+    Map<String, List<ExportEntry>> exports = 
mockAps.getCurrentExports("QuickLinks");
     Assert.assertEquals(2, exports.size());
-    Assert.assertEquals(exports.get("JMX_Endpoint"), "http://HOST1:60012/jmx";);
+    Assert.assertEquals(exports.get("JMX_Endpoint").get(0).getValue(), 
"http://HOST1:60012/jmx";);
 
     mockAps.publishConfigAndExportGroups(hb, componentStatus, "HBASE_REST");
     Mockito.verify(mockAps, Mockito.times(3)).publishApplicationInstanceData(
         anyString(),
         anyString(),
         entriesCaptor.capture());
+    PublishedExports pubExports = pubExpSet.get("QuickLinks".toLowerCase());
+    Assert.assertEquals(2, pubExports.entries.size());
+    Assert.assertEquals("QuickLinks", pubExports.description);
+    List<ExportEntry> expEntries = pubExports.entries.get("JMX_Endpoint");
+    Assert.assertEquals(1, expEntries.size());
+    Assert.assertEquals(null, expEntries.get(0).getContainerId());
+    Assert.assertEquals("application", expEntries.get(0).getLevel());
+    Assert.assertEquals(null, expEntries.get(0).getTag());
+    Assert.assertEquals("http://HOST1:60012/jmx";, 
expEntries.get(0).getValue());
+    Assert.assertNull(expEntries.get(0).getValidUntil());
+
+    expEntries = pubExports.entries.get("Master_Status");
+    Assert.assertEquals(1, expEntries.size());
+    expEntries = pubExports.entries.get("JMX_Endpoint");
+    Assert.assertEquals("http://HOST1:60012/jmx";, 
expEntries.get(0).getValue());
   }
 
   @Test
@@ -781,6 +898,7 @@ public class TestAgentProviderService {
         Assert.assertEquals(component.getCategory(), "MASTER");
         Assert.assertEquals(component.getComponentExports().size(), 0);
         Assert.assertEquals(component.getAppExports(), 
"QuickLinks-JMX_Endpoint,QuickLinks-Master_Status");
+        Assert.assertEquals(component.getCompExports(), 
"QuickLinks-Comp_Endpoint");
         found++;
       }
       if (component.getName().equals("HBASE_REGIONSERVER")) {
@@ -807,7 +925,7 @@ public class TestAgentProviderService {
     List<ExportGroup> egs = application.getExportGroups();
     ExportGroup eg = egs.get(0);
     Assert.assertEquals(eg.getName(), "QuickLinks");
-    Assert.assertEquals(eg.getExports().size(), 2);
+    Assert.assertEquals(eg.getExports().size(), 3);
 
     found = 0;
     for (Export export : eg.getExports()) {
@@ -975,15 +1093,18 @@ public class TestAgentProviderService {
           anyString(),
           anyString(),
           any(HeartBeatResponse.class));
-      doNothing().when(mockAps).publishApplicationInstanceData(
+      doNothing().when(mockAps).publishFolderPaths(
+          anyMap(),
           anyString(),
           anyString(),
-          anyCollection());
+          anyString());
       doReturn(conf).when(mockAps).getConfig();
     } catch (SliderException e) {
     }
 
+    PublishedExportsSet pubExpSet = new PublishedExportsSet();
     expect(access.isApplicationLive()).andReturn(true).anyTimes();
+    expect(access.getPublishedExportsSet()).andReturn(pubExpSet).anyTimes();
     ClusterDescription desc = new ClusterDescription();
     desc.setOption(OptionKeys.ZOOKEEPER_QUORUM, "host1:2181");
     desc.setInfo(OptionKeys.APPLICATION_NAME, "HBASE");
@@ -996,6 +1117,7 @@ public class TestAgentProviderService {
     treeOps.set(OptionKeys.APPLICATION_NAME, "HBASE");
     
expect(access.getInstanceDefinitionSnapshot()).andReturn(aggConf).anyTimes();
     expect(access.getInternalsSnapshot()).andReturn(treeOps).anyTimes();
+    doNothing().when(mockAps).publishApplicationInstanceData(anyString(), 
anyString(), anyCollection());
     replay(access, ctx, container, sliderFileSystem, mockFs);
 
     // build two containers
@@ -1094,6 +1216,7 @@ public class TestAgentProviderService {
       hb = new HeartBeat();
       hb.setResponseId(2);
       hb.setHostname("mockcontainer_1___HBASE_MASTER");
+      hb.setFqdn("host1");
       cr = new CommandReport();
       cr.setRole("HBASE_MASTER");
       cr.setRoleCommand("INSTALL");
@@ -1160,10 +1283,11 @@ public class TestAgentProviderService {
       log.warn(he.getMessage());
     }
 
-    Mockito.verify(mockAps, Mockito.times(1)).publishApplicationInstanceData(
+    Mockito.verify(mockAps, Mockito.times(1)).publishFolderPaths(
+        anyMap(),
         anyString(),
         anyString(),
-        anyCollection());
+        anyString());
   }
 
   protected AgentProviderService createAgentProviderService(Configuration 
conf) throws
@@ -1193,6 +1317,44 @@ public class TestAgentProviderService {
   }
 
   @Test
+  public void testPublishFolderPaths() throws IOException {
+    AgentProviderService aps = createAgentProviderService(new Configuration());
+    StateAccessForProviders access = 
createNiceMock(StateAccessForProviders.class);
+    AgentProviderService mockAps = Mockito.spy(aps);
+    doReturn(access).when(mockAps).getAmState();
+    PublishedExportsSet pubExpSet = new PublishedExportsSet();
+    expect(access.getPublishedExportsSet()).andReturn(pubExpSet).anyTimes();
+    replay(access);
+
+    Map<String, String> folders = new HashMap<String, String>();
+    folders.put("AGENT_LOG_ROOT", "aFolder");
+    folders.put("AGENT_WORK_ROOT", "folderB");
+    mockAps.publishFolderPaths(folders, "cid", "role", "fqdn");
+
+    PublishedExports exports = pubExpSet.get("container_log_dirs");
+    Assert.assertEquals(1, exports.entries.size());
+    List<ExportEntry> expEntries = exports.entries.get("role");
+    Assert.assertEquals(1, expEntries.size());
+    Assert.assertEquals("cid", expEntries.get(0).getContainerId());
+    Assert.assertEquals("component", expEntries.get(0).getLevel());
+    Assert.assertEquals("role", expEntries.get(0).getTag());
+    Assert.assertEquals("fqdn:aFolder", expEntries.get(0).getValue());
+    Assert.assertNull(expEntries.get(0).getValidUntil());
+    Assert.assertEquals(null, expEntries.get(0).getValidUntil());
+
+    exports = pubExpSet.get("container_work_dirs");
+    Assert.assertEquals(1, exports.entries.size());
+    expEntries = exports.entries.get("role");
+    Assert.assertEquals(1, expEntries.size());
+    Assert.assertEquals("cid", expEntries.get(0).getContainerId());
+    Assert.assertEquals("component", expEntries.get(0).getLevel());
+    Assert.assertEquals("role", expEntries.get(0).getTag());
+    Assert.assertEquals("fqdn:folderB", expEntries.get(0).getValue());
+    Assert.assertNull(expEntries.get(0).getValidUntil());
+    Assert.assertEquals(null, expEntries.get(0).getValidUntil());
+  }
+
+  @Test
   public void testNotifyContainerCompleted() throws IOException {
     AgentProviderService aps = createAgentProviderService(new Configuration());
     AgentProviderService mockAps = Mockito.spy(aps);

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/AgentCommandTestBase.groovy
----------------------------------------------------------------------
diff --git 
a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/AgentCommandTestBase.groovy
 
b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/AgentCommandTestBase.groovy
index d5448bf..db9fa6d 100644
--- 
a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/AgentCommandTestBase.groovy
+++ 
b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/AgentCommandTestBase.groovy
@@ -164,6 +164,33 @@ implements FuntestProperties, Arguments, SliderExitCodes, 
SliderActions {
     return null;
   }
 
+  public static boolean containsString(SliderShell shell, String lookThisUp, 
int n = 1) {
+    int count = 0
+    for (String str in shell.out) {
+      int subCount = countString(str, lookThisUp)
+      count = count + subCount
+      if (count == n) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  public static int countString(String str, String search) {
+    int count = 0
+    if (SliderUtils.isUnset(str) || SliderUtils.isUnset(search)) {
+      return count
+    }
+
+    int index = str.indexOf(search, 0)
+    while (index > 0) {
+      index = str.indexOf(search, index + 1)
+      ++count
+    }
+    return count
+  }
+
   public static String findLineEntryValue(SliderShell shell, String[] 
locaters) {
     String line = findLineEntry(shell, locaters);
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/31e05853/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
----------------------------------------------------------------------
diff --git 
a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
 
b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
index 234275a..0796355 100644
--- 
a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
+++ 
b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
@@ -75,6 +75,46 @@ implements FuntestProperties, Arguments, SliderExitCodes, 
SliderActions {
     assertComponentCount(COMMAND_LOGGER, 2, shell)
 
     assertSuccess(shell)
+
+    // get log folders
+    shell = slider(EXIT_SUCCESS,
+        [
+            ACTION_REGISTRY,
+            ARG_NAME,
+            APPLICATION_NAME,
+            ARG_LISTEXP])
+    if(!containsString(shell, "container_log_dirs") ||
+       !containsString(shell, "container_work_dirs")) {
+      logShell(shell)
+      assert fail("Should list default exports container_log_dirs or 
container_work_dirs")
+    }
+
+    // get log folders
+    shell = slider(EXIT_SUCCESS,
+        [
+            ACTION_REGISTRY,
+            ARG_NAME,
+            APPLICATION_NAME,
+            ARG_GETEXP,
+            "container_log_dirs"])
+    if(!containsString(shell, 
"\"tag\":\"COMMAND_LOGGER\",\"level\":\"component\"", 2)) {
+      logShell(shell)
+      assert fail("Should list 2 entries for log folders")
+    }
+
+    // get log folders
+    shell = slider(EXIT_SUCCESS,
+        [
+            ACTION_REGISTRY,
+            ARG_NAME,
+            APPLICATION_NAME,
+            ARG_GETEXP,
+            "container_work_dirs"])
+    if(!containsString(shell, 
"\"tag\":\"COMMAND_LOGGER\",\"level\":\"component\"", 2)) {
+      logShell(shell)
+      assert fail("Should list 2 entries for work folder")
+    }
+
     assert isApplicationInState("RUNNING", APPLICATION_NAME), 'App is not 
running.'
   }
 }

Reply via email to