{"action":"created","comment":{"url":"https://api.github.com/repos/codice/ddf/pulls/comments/66455175","id":66455175,"diff_hunk":"@@ -0,0 +1,699 @@\n+/**\n+ * Copyright (c) Codice Foundation\n+ * <p>\n+ * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser\n+ * General Public License as published by the Free Software Foundation, either version 3 of the\n+ * License, or any later version.\n+ * <p>\n+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\n+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details. A copy of the GNU Lesser General Public License\n+ * is distributed along with this program and can be found at\n+ * <http://www.gnu.org/licenses/lgpl.html>.\n+ */\n+package org.codice.ddf.registry.federationadmin.impl;\n+\n+import java.io.ByteArrayInputStream;\n+import java.io.ByteArrayOutputStream;\n+import java.io.File;\n+import java.io.IOException;\n+import java.io.InputStream;\n+import java.lang.management.ManagementFactory;\n+import java.nio.charset.StandardCharsets;\n+import java.nio.file.Files;\n+import java.nio.file.Path;\n+import java.nio.file.Paths;\n+import java.time.OffsetDateTime;\n+import java.time.ZoneId;\n+import java.time.ZoneOffset;\n+import java.util.ArrayList;\n+import java.util.Arrays;\n+import java.util.Base64;\n+import java.util.Collections;\n+import java.util.Dictionary;\n+import java.util.HashMap;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Optional;\n+import java.util.UUID;\n+import java.util.stream.Collectors;\n+\n+import javax.management.InstanceAlreadyExistsException;\n+import javax.management.MBeanServer;\n+import javax.management.MalformedObjectNameException;\n+import javax.management.ObjectName;\n+import javax.management.StandardMBean;\n+import javax.xml.bind.JAXBElement;\n+import javax.xml.bind.Marshaller;\n+import javax.xml.datatype.DatatypeConstants;\n+\n+import org.apache.commons.collections.CollectionUtils;\n+import org.apache.commons.collections.MapUtils;\n+import org.apache.commons.lang.StringUtils;\n+import org.codice.ddf.configuration.SystemBaseUrl;\n+import org.codice.ddf.parser.Parser;\n+import org.codice.ddf.parser.ParserConfigurator;\n+import org.codice.ddf.parser.ParserException;\n+import org.codice.ddf.registry.common.RegistryConstants;\n+import org.codice.ddf.registry.common.metacard.RegistryObjectMetacardType;\n+import org.codice.ddf.registry.federationadmin.FederationAdminMBean;\n+import org.codice.ddf.registry.federationadmin.service.FederationAdminException;\n+import org.codice.ddf.registry.federationadmin.service.FederationAdminService;\n+import org.codice.ddf.registry.schemabindings.EbrimConstants;\n+import org.codice.ddf.registry.schemabindings.converter.type.RegistryPackageTypeConverter;\n+import org.codice.ddf.registry.schemabindings.converter.web.RegistryPackageWebConverter;\n+import org.codice.ddf.registry.schemabindings.helper.SlotTypeHelper;\n+import org.osgi.framework.Bundle;\n+import org.osgi.framework.BundleContext;\n+import org.osgi.framework.FrameworkUtil;\n+import org.osgi.framework.InvalidSyntaxException;\n+import org.osgi.framework.ServiceReference;\n+import org.osgi.service.cm.Configuration;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import com.google.gson.Gson;\n+\n+import ddf.catalog.data.Attribute;\n+import ddf.catalog.data.Metacard;\n+import ddf.catalog.data.impl.AttributeImpl;\n+import ddf.catalog.endpoint.CatalogEndpoint;\n+import ddf.catalog.service.ConfiguredService;\n+import ddf.catalog.source.Source;\n+import ddf.catalog.transform.CatalogTransformerException;\n+import ddf.catalog.transform.InputTransformer;\n+import oasis.names.tc.ebxml_regrep.xsd.rim._3.ExtrinsicObjectType;\n+import oasis.names.tc.ebxml_regrep.xsd.rim._3.RegistryObjectType;\n+import oasis.names.tc.ebxml_regrep.xsd.rim._3.RegistryPackageType;\n+import oasis.names.tc.ebxml_regrep.xsd.rim._3.SlotType1;\n+import oasis.names.tc.ebxml_regrep.xsd.rim._3.ValueListType;\n+\n+public class FederationAdmin implements FederationAdminMBean {\n+\n+    private static final Logger LOGGER = LoggerFactory.getLogger(FederationAdmin.class);\n+\n+    private static final String MAP_ENTRY_ID = \"id\";\n+\n+    private static final String MAP_ENTRY_ENABLED = \"enabled\";\n+\n+    private static final String MAP_ENTRY_FPID = \"fpid\";\n+\n+    private static final String MAP_ENTRY_NAME = \"name\";\n+\n+    private static final String MAP_ENTRY_BUNDLE_NAME = \"bundle_name\";\n+\n+    private static final String MAP_ENTRY_BUNDLE_LOCATION = \"bundle_location\";\n+\n+    private static final String MAP_ENTRY_BUNDLE = \"bundle\";\n+\n+    private static final String MAP_ENTRY_PROPERTIES = \"properties\";\n+\n+    private static final String MAP_ENTRY_CONFIGURATIONS = \"configurations\";\n+\n+    private static final String DISABLED = \"_disabled\";\n+\n+    private static final String TRANSIENT_VALUES_KEY = \"TransientValues\";\n+\n+    private static final String AUTO_POPULATE_VALUES_KEY = \"autoPopulateValues\";\n+\n+    private static final String SERVICE_BINDINGS_KEY = \"ServiceBinding\";\n+\n+    private static final String CUSTOM_SLOTS_KEY = \"customSlots\";\n+\n+    private static final String NODES_KEY = \"nodes\";\n+\n+    private static final String KARAF_ETC = \"karaf.etc\";\n+\n+    private static final String REGISTRY_CONFIG_DIR = \"registry\";\n+\n+    private static final String REGISTRY_FIELDS_FILE = \"registry-custom-slots.json\";\n+\n+    private MBeanServer mbeanServer;\n+\n+    private ObjectName objectName;\n+\n+    private FederationAdminService federationAdminService;\n+\n+    private InputTransformer registryTransformer;\n+\n+    private Parser parser;\n+\n+    private ParserConfigurator marshalConfigurator;\n+\n+    private AdminHelper helper;\n+\n+    private Map<String, Object> customSlots;\n+\n+    private Map<String, Map<String, String>> endpointMap = new HashMap<>();\n+\n+    private RegistryPackageTypeConverter registryTypeConverter;\n+\n+    private RegistryPackageWebConverter registryMapConverter;\n+\n+    private SlotTypeHelper slotHelper;\n+\n+    public FederationAdmin(AdminHelper helper) {\n+        configureMBean();\n+        this.helper = helper;\n+    }\n+\n+    @Override\n+    public String createLocalEntry(Map<String, Object> registryMap)\n+            throws FederationAdminException {\n+\n+        Optional<RegistryPackageType> registryPackageOptional = registryTypeConverter.convert(\n+                registryMap);\n+        RegistryPackageType registryPackage =\n+                registryPackageOptional.orElseThrow(() -> new FederationAdminException(\n+                        \"Error creating local registry entry. Couldn't convert registry map to a registry package.\"));\n+\n+        if (!registryPackage.isSetHome()) {\n+            registryPackage.setHome(SystemBaseUrl.getBaseUrl());\n+        }\n+\n+        if (!registryPackage.isSetObjectType()) {\n+            registryPackage.setObjectType(RegistryConstants.REGISTRY_NODE_OBJECT_TYPE);\n+        }\n+\n+        if (!registryPackage.isSetId()) {\n+            String registryPackageId = RegistryConstants.GUID_PREFIX + UUID.randomUUID()\n+                    .toString()\n+                    .replaceAll(\"-\", \"\");\n+            registryPackage.setId(registryPackageId);\n+        }\n+\n+        updateDateFields(registryPackage);\n+\n+        Metacard metacard = getRegistryMetacardFromRegistryPackage(registryPackage);\n+        metacard.setAttribute(new AttributeImpl(RegistryObjectMetacardType.REGISTRY_LOCAL_NODE,\n+                true));\n+        return federationAdminService.addRegistryEntry(metacard);\n+    }\n+\n+    @Override\n+    public String createLocalEntry(String base64EncodedXmlData) throws FederationAdminException {\n+        if (StringUtils.isBlank(base64EncodedXmlData)) {\n+            throw new FederationAdminException(\n+                    \"Error creating local entry. String provided was blank.\");\n+        }\n+\n+        String metacardId;\n+        try (InputStream xmlStream = new ByteArrayInputStream(Base64.getDecoder()\n+                .decode(base64EncodedXmlData))) {\n+            Metacard metacard = getRegistryMetacardFromInputStream(xmlStream);\n+            metacard.setAttribute(new AttributeImpl(RegistryObjectMetacardType.REGISTRY_LOCAL_NODE,\n+                    true));\n+            metacardId = federationAdminService.addRegistryEntry(metacard);\n+        } catch (IOException | IllegalArgumentException e) {\n+            String message = \"Error creating local entry. Couldn't decode string.\";\n+            LOGGER.error(\"{} Base64 encoded xml: {}\", message, base64EncodedXmlData);\n+            throw new FederationAdminException(message, e);\n+        }\n+        return metacardId;\n+    }\n+\n+    @Override\n+    public void updateLocalEntry(Map<String, Object> registryObjectMap)\n+            throws FederationAdminException {\n+\n+        Optional<RegistryPackageType> registryPackageOptional = registryTypeConverter.convert(\n+                registryObjectMap);\n+        RegistryPackageType registryPackage =\n+                registryPackageOptional.orElseThrow(() -> new FederationAdminException(\n+                        \"Error updating local registry entry. Couldn't convert registry map to a registry package.\"));\n+\n+        updateDateFields(registryPackage);\n+\n+        List<Metacard> existingMetacards =\n+                federationAdminService.getLocalRegistryMetacardsByRegistryIds(Collections.singletonList(\n+                        registryPackage.getId()));\n+\n+        if (CollectionUtils.isEmpty(existingMetacards)) {\n+            String message = \"Error updating local registry entry. Registry metacard not found.\";\n+            LOGGER.error(\"{} Registry ID: {}\", message, registryPackage.getId());\n+            throw new FederationAdminException(message);\n+        }\n+\n+        if (existingMetacards.size() > 1) {\n+            String message =\n+                    \"Error updating local registry entry. Multiple registry metacards found.\";\n+\n+            List<String> metacardIds = new ArrayList<>();\n+            metacardIds.addAll(existingMetacards.stream()\n+                    .map(Metacard::getId)\n+                    .collect(Collectors.toList()));\n+            LOGGER.error(\"{} Matching registry metacard ids: {}\", message, metacardIds);\n+\n+            throw new FederationAdminException(message);\n+        }\n+        Metacard existingMetacard = existingMetacards.get(0);\n+\n+        Metacard updateMetacard = getRegistryMetacardFromRegistryPackage(registryPackage);\n+        updateMetacard.setAttribute(new AttributeImpl(Metacard.ID, existingMetacard.getId()));\n+\n+        federationAdminService.updateRegistryEntry(updateMetacard);\n+    }\n+\n+    @Override\n+    public void deleteLocalEntry(List<String> ids) throws FederationAdminException {\n+        if (CollectionUtils.isEmpty(ids)) {\n+            throw new FederationAdminException(\n+                    \"Error deleting local registry entries. No ids provided.\");\n+        }\n+\n+        List<Metacard> localMetacards =\n+                federationAdminService.getLocalRegistryMetacardsByRegistryIds(ids);\n+        List<String> metacardIds = new ArrayList<>();\n+\n+        metacardIds.addAll(localMetacards.stream()\n+                .map(Metacard::getId)\n+                .collect(Collectors.toList()));\n+        if (ids.size() != metacardIds.size()) {\n+            String message = \"Error deleting local registry entries. Registry ids provided.\";\n+            LOGGER.error(\"{} Registry Ids provided: {}. Registry metacard ids found: {}\",\n+                    message,\n+                    ids,\n+                    metacardIds);\n+            throw new FederationAdminException(message);\n+        }\n+\n+        federationAdminService.deleteRegistryEntriesByMetacardIds(metacardIds);\n+    }\n+\n+    @Override\n+    public Map<String, Object> getLocalNodes() throws FederationAdminException {\n+        Map<String, Object> localNodes = new HashMap<>();\n+        List<Map<String, Object>> registryWebMaps = new ArrayList<>();\n+\n+        List<RegistryPackageType> registryPackages =\n+                federationAdminService.getLocalRegistryObjects();\n+\n+        List<Metacard> metacards = federationAdminService.getLocalRegistryMetacards();\n+        Map<String, Metacard> metacardByRegistryIdMap = getRegistryIdMetacardMap(metacards);\n+\n+        registryWebMaps = getWebMapsFromRegistryPackages(registryPackages, metacardByRegistryIdMap);\n+\n+        if (customSlots != null) {\n+            localNodes.put(CUSTOM_SLOTS_KEY, customSlots);\n+        }\n+\n+        Map<String, Object> autoPopulateMap = new HashMap<>();\n+        autoPopulateMap.put(SERVICE_BINDINGS_KEY, endpointMap.values());\n+        localNodes.put(AUTO_POPULATE_VALUES_KEY, autoPopulateMap);\n+\n+        localNodes.put(NODES_KEY, registryWebMaps);\n+\n+        return localNodes;\n+    }\n+\n+    @Override\n+    public boolean registryStatus(String servicePID) {\n+        try {\n+            List<Source> sources = helper.getRegistrySources();\n+            for (Source source : sources) {\n+                if (source instanceof ConfiguredService) {\n+                    ConfiguredService cs = (ConfiguredService) source;\n+                    try {\n+                        Configuration config = helper.getConfiguration(cs);\n+                        if (config != null && config.getProperties()\n+                                .get(\"service.pid\")\n+                                .equals(servicePID)) {\n+                            try {\n+                                return source.isAvailable();\n+                            } catch (Exception e) {\n+                                LOGGER.warn(\"Couldn't get availability on registry {}: {}\",\n+                                        servicePID,\n+                                        e);\n+                            }\n+                        }\n+                    } catch (IOException e) {\n+                        LOGGER.warn(\"Couldn't find configuration for source '{}'\", source.getId());\n+                    }\n+                } else {\n+                    LOGGER.warn(\"Source '{}' not a configured service\", source.getId());\n+                }\n+            }\n+        } catch (InvalidSyntaxException e) {\n+            LOGGER.error(\"Could not get service reference list\");\n+        }\n+\n+        return false;\n+    }\n+\n+    @Override\n+    public List<Map<String, Object>> allRegistryInfo() {\n+\n+        List<Map<String, Object>> metatypes = helper.getMetatypes();\n+\n+        for (Map metatype : metatypes) {\n+            try {\n+                List<Configuration> configs = helper.getConfigurations(metatype);\n+\n+                ArrayList<Map<String, Object>> configurations = new ArrayList<>();\n+                if (configs != null) {\n+                    for (Configuration config : configs) {\n+                        Map<String, Object> registry = new HashMap<>();\n+\n+                        boolean disabled = config.getPid()\n+                                .contains(DISABLED);\n+                        registry.put(MAP_ENTRY_ID, config.getPid());\n+                        registry.put(MAP_ENTRY_ENABLED, !disabled);\n+                        registry.put(MAP_ENTRY_FPID, config.getFactoryPid());\n+\n+                        if (!disabled) {\n+                            registry.put(MAP_ENTRY_NAME, helper.getName(config));\n+                            registry.put(MAP_ENTRY_BUNDLE_NAME, helper.getBundleName(config));\n+                            registry.put(MAP_ENTRY_BUNDLE_LOCATION, config.getBundleLocation());\n+                            registry.put(MAP_ENTRY_BUNDLE, helper.getBundleId(config));\n+                        } else {\n+                            registry.put(MAP_ENTRY_NAME, config.getPid());\n+                        }\n+\n+                        Dictionary<String, Object> properties = config.getProperties();\n+                        Map<String, Object> plist = new HashMap<>();\n+                        for (String key : Collections.list(properties.keys())) {\n+                            plist.put(key, properties.get(key));\n+                        }\n+                        registry.put(MAP_ENTRY_PROPERTIES, plist);\n+\n+                        configurations.add(registry);\n+                    }\n+                    metatype.put(MAP_ENTRY_CONFIGURATIONS, configurations);\n+                }\n+            } catch (InvalidSyntaxException | IOException e) {\n+                LOGGER.warn(\"Error getting registry info: {}\", e.getMessage());\n+            }\n+        }\n+\n+        Collections.sort(metatypes,\n+                (o1, o2) -> ((String) o1.get(\"id\")).compareToIgnoreCase((String) o2.get(\"id\")));\n+        return metatypes;\n+    }\n+\n+    @Override\n+    public Map<String, Object> allRegistryMetacards() {\n+        Map<String, Object> nodes = new HashMap<>();\n+        List<Map<String, Object>> registryMetacardInfo = new ArrayList<>();\n+\n+        try {\n+            List<RegistryPackageType> registryMetacardObjects =\n+                    federationAdminService.getRegistryObjects();\n+\n+            List<Metacard> metacards = federationAdminService.getRegistryMetacards();\n+            Map<String, Metacard> metacardByRegistryIdMap = getRegistryIdMetacardMap(metacards);\n+\n+            registryMetacardInfo = getWebMapsFromRegistryPackages(registryMetacardObjects,\n+                    metacardByRegistryIdMap);\n+\n+        } catch (FederationAdminException e) {\n+            LOGGER.warn(\"Couldn't get remote registry metacards '{}'\", e);\n+        }\n+\n+        if (customSlots != null) {\n+            nodes.put(CUSTOM_SLOTS_KEY, customSlots);\n+        }\n+\n+        Map<String, Object> autoPopulateMap = new HashMap<>();\n+        autoPopulateMap.put(SERVICE_BINDINGS_KEY, endpointMap.values());\n+        nodes.put(AUTO_POPULATE_VALUES_KEY, autoPopulateMap);\n+\n+        nodes.put(NODES_KEY, registryMetacardInfo);\n+\n+        return nodes;\n+    }\n+\n+    private List<Map<String, Object>> getWebMapsFromRegistryPackages(\n+            List<RegistryPackageType> packages, Map<String, Metacard> metacardByRegistryIdMap) {\n+        List<Map<String, Object>> registryMaps = new ArrayList<>();\n+        for (RegistryPackageType registryPackage : packages) {\n+            Map<String, Object> registryWebMap = registryMapConverter.convert(registryPackage);\n+\n+            Metacard metacard = metacardByRegistryIdMap.get(registryPackage.getId());\n+            Map<String, Object> transientValues = getTransientValuesMap(metacard);\n+            if (MapUtils.isNotEmpty(transientValues)) {\n+                registryWebMap.put(TRANSIENT_VALUES_KEY, transientValues);\n+            }\n+\n+            if (MapUtils.isNotEmpty(registryWebMap)) {\n+                registryMaps.add(registryWebMap);\n+            }\n+        }\n+        return registryMaps;\n+    }\n+\n+    private Metacard getRegistryMetacardFromRegistryPackage(RegistryPackageType registryPackage)\n+            throws FederationAdminException {\n+        if (registryPackage == null) {\n+            throw new FederationAdminException(\n+                    \"Error creating metacard from registry package. Null package was received.\");\n+        }\n+        Metacard metacard;\n+\n+        try {\n+            JAXBElement<RegistryPackageType> jaxbRegistryObjectType =\n+                    EbrimConstants.RIM_FACTORY.createRegistryPackage(registryPackage);\n+","path":"catalog/spatial/registry/registry-federation-admin-impl/src/main/java/org/codice/ddf/registry/federationadmin/impl/FederationAdmin.java","position":447,"original_position":455,"commit_id":"df03881c2d77688c84ae950f16cf2853a9537e1a","original_commit_id":"9cafecc55317707e730f42ec055706898861da0f","user":{"login":"clockard","id":5248090,"avatar_url":"https://avatars.githubusercontent.com/u/5248090?v=3","gravatar_id":"","url":"https://api.github.com/users/clockard","html_url":"https://github.com/clockard","followers_url":"https://api.github.com/users/clockard/followers","following_url":"https://api.github.com/users/clockard/following{/other_user}","gists_url":"https://api.github.com/users/clockard/gists{/gist_id}","starred_url":"https://api.github.com/users/clockard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clockard/subscriptions","organizations_url":"https://api.github.com/users/clockard/orgs","repos_url":"https://api.github.com/users/clockard/repos","events_url":"https://api.github.com/users/clockard/events{/privacy}","received_events_url":"https://api.github.com/users/clockard/received_events","type":"User","site_admin":false},"body":"PR https://github.com/codice/ddf/pull/810 creates a helper that this chunk of code will be replaced with. The helper has the close in the finally block","created_at":"2016-06-09T14:48:34Z","updated_at":"2016-06-09T14:48:34Z","html_url":"https://github.com/codice/ddf/pull/812#discussion_r66455175","pull_request_url":"https://api.github.com/repos/codice/ddf/pulls/812","_links":{"self":{"href":"https://api.github.com/repos/codice/ddf/pulls/comments/66455175"},"html":{"href":"https://github.com/codice/ddf/pull/812#discussion_r66455175"},"pull_request":{"href":"https://api.github.com/repos/codice/ddf/pulls/812"}}},"pull_request":{"url":"https://api.github.com/repos/codice/ddf/pulls/812","id":71247918,"html_url":"https://github.com/codice/ddf/pull/812","diff_url":"https://github.com/codice/ddf/pull/812.diff","patch_url":"https://github.com/codice/ddf/pull/812.patch","issue_url":"https://api.github.com/repos/codice/ddf/issues/812","number":812,"state":"open","locked":false,"title":"DDF-2101 Created registry-federation-admin-impl to enable UI access to registry features","user":{"login":"clockard","id":5248090,"avatar_url":"https://avatars.githubusercontent.com/u/5248090?v=3","gravatar_id":"","url":"https://api.github.com/users/clockard","html_url":"https://github.com/clockard","followers_url":"https://api.github.com/users/clockard/followers","following_url":"https://api.github.com/users/clockard/following{/other_user}","gists_url":"https://api.github.com/users/clockard/gists{/gist_id}","starred_url":"https://api.github.com/users/clockard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clockard/subscriptions","organizations_url":"https://api.github.com/users/clockard/orgs","repos_url":"https://api.github.com/users/clockard/repos","events_url":"https://api.github.com/users/clockard/events{/privacy}","received_events_url":"https://api.github.com/users/clockard/received_events","type":"User","site_admin":false},"body":"#### What does this PR do?\r\nAdds the registry-federation-admin-impl module which provides an mbean for accessing/update registry information. This is an initial PR and can't be heroed or built until other peer PRs are merged.\r\n#### Who is reviewing it (please choose AT LEAST two reviewers that need to approve the PR before it can get merged; if a component team is listed, at least one of its members needs to approve)?\r\n@AzGoalie @spearskw \r\n#### Choose 2 committers to review/merge the PR (please choose ONLY two committers from below, delete the rest).\r\n@figliold \r\n@stustison\r\n#### How should this be tested?\r\nOutside of unit/itests \r\n1) Bring up an instance of DDF and start the DDF Registry app\r\n2) Hit the endpoint https://localhost:8993/admin/jolokia/read/org.codice.ddf.registry:type=FederationAdminMBean/LocalNodes\r\n3) Verify that you get a response back that has the following\r\n - one identity node in the 'nodes' array\r\n - six entries in the custom slots\r\n - two entries in the auto populate service bindings\r\n\r\n#### Any background context you want to provide?\r\nThis module is coming over from the ddf-registry repo.\r\n#### What are the relevant tickets?\r\nDDF-2101\r\n#### Screenshots (if appropriate)\r\n#### Checklist:\r\n- [ ] Documentation Updated\r\n- [X] Update / Add Unit Tests\r\n- [ ] Update / Add Integration Tests","created_at":"2016-05-24T16:04:52Z","updated_at":"2016-06-09T14:48:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"169a43b937bffbae2c4a5a10168865806ad468c6","assignee":{"login":"stustison","id":4391679,"avatar_url":"https://avatars.githubusercontent.com/u/4391679?v=3","gravatar_id":"","url":"https://api.github.com/users/stustison","html_url":"https://github.com/stustison","followers_url":"https://api.github.com/users/stustison/followers","following_url":"https://api.github.com/users/stustison/following{/other_user}","gists_url":"https://api.github.com/users/stustison/gists{/gist_id}","starred_url":"https://api.github.com/users/stustison/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stustison/subscriptions","organizations_url":"https://api.github.com/users/stustison/orgs","repos_url":"https://api.github.com/users/stustison/repos","events_url":"https://api.github.com/users/stustison/events{/privacy}","received_events_url":"https://api.github.com/users/stustison/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/codice/ddf/pulls/812/commits","review_comments_url":"https://api.github.com/repos/codice/ddf/pulls/812/comments","review_comment_url":"https://api.github.com/repos/codice/ddf/pulls/comments{/number}","comments_url":"https://api.github.com/repos/codice/ddf/issues/812/comments","statuses_url":"https://api.github.com/repos/codice/ddf/statuses/df03881c2d77688c84ae950f16cf2853a9537e1a","head":{"label":"clockard:DDF-2101","ref":"DDF-2101","sha":"df03881c2d77688c84ae950f16cf2853a9537e1a","user":{"login":"clockard","id":5248090,"avatar_url":"https://avatars.githubusercontent.com/u/5248090?v=3","gravatar_id":"","url":"https://api.github.com/users/clockard","html_url":"https://github.com/clockard","followers_url":"https://api.github.com/users/clockard/followers","following_url":"https://api.github.com/users/clockard/following{/other_user}","gists_url":"https://api.github.com/users/clockard/gists{/gist_id}","starred_url":"https://api.github.com/users/clockard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clockard/subscriptions","organizations_url":"https://api.github.com/users/clockard/orgs","repos_url":"https://api.github.com/users/clockard/repos","events_url":"https://api.github.com/users/clockard/events{/privacy}","received_events_url":"https://api.github.com/users/clockard/received_events","type":"User","site_admin":false},"repo":{"id":33900871,"name":"ddf","full_name":"clockard/ddf","owner":{"login":"clockard","id":5248090,"avatar_url":"https://avatars.githubusercontent.com/u/5248090?v=3","gravatar_id":"","url":"https://api.github.com/users/clockard","html_url":"https://github.com/clockard","followers_url":"https://api.github.com/users/clockard/followers","following_url":"https://api.github.com/users/clockard/following{/other_user}","gists_url":"https://api.github.com/users/clockard/gists{/gist_id}","starred_url":"https://api.github.com/users/clockard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clockard/subscriptions","organizations_url":"https://api.github.com/users/clockard/orgs","repos_url":"https://api.github.com/users/clockard/repos","events_url":"https://api.github.com/users/clockard/events{/privacy}","received_events_url":"https://api.github.com/users/clockard/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/clockard/ddf","description":"The Distributed Data Framework - Distribution, SDK, and Test","fork":true,"url":"https://api.github.com/repos/clockard/ddf","forks_url":"https://api.github.com/repos/clockard/ddf/forks","keys_url":"https://api.github.com/repos/clockard/ddf/keys{/key_id}","collaborators_url":"https://api.github.com/repos/clockard/ddf/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/clockard/ddf/teams","hooks_url":"https://api.github.com/repos/clockard/ddf/hooks","issue_events_url":"https://api.github.com/repos/clockard/ddf/issues/events{/number}","events_url":"https://api.github.com/repos/clockard/ddf/events","assignees_url":"https://api.github.com/repos/clockard/ddf/assignees{/user}","branches_url":"https://api.github.com/repos/clockard/ddf/branches{/branch}","tags_url":"https://api.github.com/repos/clockard/ddf/tags","blobs_url":"https://api.github.com/repos/clockard/ddf/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/clockard/ddf/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/clockard/ddf/git/refs{/sha}","trees_url":"https://api.github.com/repos/clockard/ddf/git/trees{/sha}","statuses_url":"https://api.github.com/repos/clockard/ddf/statuses/{sha}","languages_url":"https://api.github.com/repos/clockard/ddf/languages","stargazers_url":"https://api.github.com/repos/clockard/ddf/stargazers","contributors_url":"https://api.github.com/repos/clockard/ddf/contributors","subscribers_url":"https://api.github.com/repos/clockard/ddf/subscribers","subscription_url":"https://api.github.com/repos/clockard/ddf/subscription","commits_url":"https://api.github.com/repos/clockard/ddf/commits{/sha}","git_commits_url":"https://api.github.com/repos/clockard/ddf/git/commits{/sha}","comments_url":"https://api.github.com/repos/clockard/ddf/comments{/number}","issue_comment_url":"https://api.github.com/repos/clockard/ddf/issues/comments{/number}","contents_url":"https://api.github.com/repos/clockard/ddf/contents/{+path}","compare_url":"https://api.github.com/repos/clockard/ddf/compare/{base}...{head}","merges_url":"https://api.github.com/repos/clockard/ddf/merges","archive_url":"https://api.github.com/repos/clockard/ddf/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/clockard/ddf/downloads","issues_url":"https://api.github.com/repos/clockard/ddf/issues{/number}","pulls_url":"https://api.github.com/repos/clockard/ddf/pulls{/number}","milestones_url":"https://api.github.com/repos/clockard/ddf/milestones{/number}","notifications_url":"https://api.github.com/repos/clockard/ddf/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/clockard/ddf/labels{/name}","releases_url":"https://api.github.com/repos/clockard/ddf/releases{/id}","deployments_url":"https://api.github.com/repos/clockard/ddf/deployments","created_at":"2015-04-14T00:06:27Z","updated_at":"2016-01-14T17:17:40Z","pushed_at":"2016-06-08T19:10:36Z","git_url":"git://github.com/clockard/ddf.git","ssh_url":"git@github.com:clockard/ddf.git","clone_url":"https://github.com/clockard/ddf.git","svn_url":"https://github.com/clockard/ddf","homepage":"","size":143456,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"codice:master","ref":"master","sha":"40a5b529d867572389aedf07bfa4cf1ba0d6bf37","user":{"login":"codice","id":2386734,"avatar_url":"https://avatars.githubusercontent.com/u/2386734?v=3","gravatar_id":"","url":"https://api.github.com/users/codice","html_url":"https://github.com/codice","followers_url":"https://api.github.com/users/codice/followers","following_url":"https://api.github.com/users/codice/following{/other_user}","gists_url":"https://api.github.com/users/codice/gists{/gist_id}","starred_url":"https://api.github.com/users/codice/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codice/subscriptions","organizations_url":"https://api.github.com/users/codice/orgs","repos_url":"https://api.github.com/users/codice/repos","events_url":"https://api.github.com/users/codice/events{/privacy}","received_events_url":"https://api.github.com/users/codice/received_events","type":"Organization","site_admin":false},"repo":{"id":15173563,"name":"ddf","full_name":"codice/ddf","owner":{"login":"codice","id":2386734,"avatar_url":"https://avatars.githubusercontent.com/u/2386734?v=3","gravatar_id":"","url":"https://api.github.com/users/codice","html_url":"https://github.com/codice","followers_url":"https://api.github.com/users/codice/followers","following_url":"https://api.github.com/users/codice/following{/other_user}","gists_url":"https://api.github.com/users/codice/gists{/gist_id}","starred_url":"https://api.github.com/users/codice/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codice/subscriptions","organizations_url":"https://api.github.com/users/codice/orgs","repos_url":"https://api.github.com/users/codice/repos","events_url":"https://api.github.com/users/codice/events{/privacy}","received_events_url":"https://api.github.com/users/codice/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/codice/ddf","description":"Distributed Data Framework - an open source, modular integration framework.","fork":false,"url":"https://api.github.com/repos/codice/ddf","forks_url":"https://api.github.com/repos/codice/ddf/forks","keys_url":"https://api.github.com/repos/codice/ddf/keys{/key_id}","collaborators_url":"https://api.github.com/repos/codice/ddf/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/codice/ddf/teams","hooks_url":"https://api.github.com/repos/codice/ddf/hooks","issue_events_url":"https://api.github.com/repos/codice/ddf/issues/events{/number}","events_url":"https://api.github.com/repos/codice/ddf/events","assignees_url":"https://api.github.com/repos/codice/ddf/assignees{/user}","branches_url":"https://api.github.com/repos/codice/ddf/branches{/branch}","tags_url":"https://api.github.com/repos/codice/ddf/tags","blobs_url":"https://api.github.com/repos/codice/ddf/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/codice/ddf/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/codice/ddf/git/refs{/sha}","trees_url":"https://api.github.com/repos/codice/ddf/git/trees{/sha}","statuses_url":"https://api.github.com/repos/codice/ddf/statuses/{sha}","languages_url":"https://api.github.com/repos/codice/ddf/languages","stargazers_url":"https://api.github.com/repos/codice/ddf/stargazers","contributors_url":"https://api.github.com/repos/codice/ddf/contributors","subscribers_url":"https://api.github.com/repos/codice/ddf/subscribers","subscription_url":"https://api.github.com/repos/codice/ddf/subscription","commits_url":"https://api.github.com/repos/codice/ddf/commits{/sha}","git_commits_url":"https://api.github.com/repos/codice/ddf/git/commits{/sha}","comments_url":"https://api.github.com/repos/codice/ddf/comments{/number}","issue_comment_url":"https://api.github.com/repos/codice/ddf/issues/comments{/number}","contents_url":"https://api.github.com/repos/codice/ddf/contents/{+path}","compare_url":"https://api.github.com/repos/codice/ddf/compare/{base}...{head}","merges_url":"https://api.github.com/repos/codice/ddf/merges","archive_url":"https://api.github.com/repos/codice/ddf/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/codice/ddf/downloads","issues_url":"https://api.github.com/repos/codice/ddf/issues{/number}","pulls_url":"https://api.github.com/repos/codice/ddf/pulls{/number}","milestones_url":"https://api.github.com/repos/codice/ddf/milestones{/number}","notifications_url":"https://api.github.com/repos/codice/ddf/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/codice/ddf/labels{/name}","releases_url":"https://api.github.com/repos/codice/ddf/releases{/id}","deployments_url":"https://api.github.com/repos/codice/ddf/deployments","created_at":"2013-12-13T20:38:28Z","updated_at":"2016-06-09T11:41:29Z","pushed_at":"2016-06-09T14:22:19Z","git_url":"git://github.com/codice/ddf.git","ssh_url":"git@github.com:codice/ddf.git","clone_url":"https://github.com/codice/ddf.git","svn_url":"https://github.com/codice/ddf","homepage":"http://ddf.codice.org","size":271239,"stargazers_count":38,"watchers_count":38,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":80,"mirror_url":null,"open_issues_count":23,"forks":80,"open_issues":23,"watchers":38,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/codice/ddf/pulls/812"},"html":{"href":"https://github.com/codice/ddf/pull/812"},"issue":{"href":"https://api.github.com/repos/codice/ddf/issues/812"},"comments":{"href":"https://api.github.com/repos/codice/ddf/issues/812/comments"},"review_comments":{"href":"https://api.github.com/repos/codice/ddf/pulls/812/comments"},"review_comment":{"href":"https://api.github.com/repos/codice/ddf/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/codice/ddf/pulls/812/commits"},"statuses":{"href":"https://api.github.com/repos/codice/ddf/statuses/df03881c2d77688c84ae950f16cf2853a9537e1a"}}}}
{"actor":{"display_login":"clockard"}}