@Override
	public void exportData(JsonWriter writer) throws IOException {

		// version tag at the root
		writer.name(THIS_VERSION);

		writer.beginObject();

		// clients list
		writer.name(CLIENTS);
		writer.beginArray();
		writeClients(writer);
		writer.endArray();

		writer.name(GRANTS);
		writer.beginArray();
		writeGrants(writer);
		writer.endArray();

		writer.name(WHITELISTEDSITES);
		writer.beginArray();
		writeWhitelistedSites(writer);
		writer.endArray();

		writer.name(BLACKLISTEDSITES);
		writer.beginArray();
		writeBlacklistedSites(writer);
		writer.endArray();

		writer.name(AUTHENTICATIONHOLDERS);
		writer.beginArray();
		writeAuthenticationHolders(writer);
		writer.endArray();

		writer.name(ACCESSTOKENS);
		writer.beginArray();
		writeAccessTokens(writer);
		writer.endArray();

		writer.name(REFRESHTOKENS);
		writer.beginArray();
		writeRefreshTokens(writer);
		writer.endArray();

		writer.name(SYSTEMSCOPES);
		writer.beginArray();
		writeSystemScopes(writer);
		writer.endArray();

		for (MITREidDataServiceExtension extension : extensions) {
			if (extension.supportsVersion(THIS_VERSION)) {
				extension.exportExtensionData(writer);
				break;
			}
		}

		writer.endObject(); // end mitreid-connect-1.3
	}
@Test
	public void testExportClients() throws IOException {
		ClientDetailsEntity client1 = new ClientDetailsEntity();
		client1.setId(1L);
		client1.setAccessTokenValiditySeconds(3600);
		client1.setClientId("client1");
		client1.setClientSecret("clientsecret1");
		client1.setRedirectUris(ImmutableSet.of("http://foo.com/"));
		client1.setScope(ImmutableSet.of("foo", "bar", "baz", "dolphin"));
		client1.setGrantTypes(ImmutableSet.of("implicit", "authorization_code", "urn:ietf:params:oauth:grant_type:redelegate", "refresh_token"));
		client1.setAllowIntrospection(true);

		ClientDetailsEntity client2 = new ClientDetailsEntity();
		client2.setId(2L);
		client2.setAccessTokenValiditySeconds(3600);
		client2.setClientId("client2");
		client2.setClientSecret("clientsecret2");
		client2.setRedirectUris(ImmutableSet.of("http://bar.baz.com/"));
		client2.setScope(ImmutableSet.of("foo", "dolphin", "electric-wombat"));
		client2.setGrantTypes(ImmutableSet.of("client_credentials", "urn:ietf:params:oauth:grant_type:redelegate"));
		client2.setAllowIntrospection(false);
		client2.setCodeChallengeMethod(PKCEAlgorithm.S256);

		Set<ClientDetailsEntity> allClients = ImmutableSet.of(client1, client2);

		Mockito.when(clientRepository.getAllClients()).thenReturn(allClients);
		Mockito.when(approvedSiteRepository.getAll()).thenReturn(new HashSet<ApprovedSite>());
		Mockito.when(wlSiteRepository.getAll()).thenReturn(new HashSet<WhitelistedSite>());
		Mockito.when(blSiteRepository.getAll()).thenReturn(new HashSet<BlacklistedSite>());
		Mockito.when(authHolderRepository.getAll()).thenReturn(new ArrayList<AuthenticationHolderEntity>());
		Mockito.when(tokenRepository.getAllAccessTokens()).thenReturn(new HashSet<OAuth2AccessTokenEntity>());
		Mockito.when(tokenRepository.getAllRefreshTokens()).thenReturn(new HashSet<OAuth2RefreshTokenEntity>());
		Mockito.when(sysScopeRepository.getAll()).thenReturn(new HashSet<SystemScope>());

		// do the data export
		StringWriter stringWriter = new StringWriter();
		JsonWriter writer = new JsonWriter(stringWriter);
		writer.beginObject();
		dataService.exportData(writer);
		writer.endObject();
		writer.close();

		// parse the output as a JSON object for testing
		JsonElement elem = new JsonParser().parse(stringWriter.toString());
		JsonObject root = elem.getAsJsonObject();

		// make sure the root is there
		assertThat(root.has(MITREidDataService.MITREID_CONNECT_1_3), is(true));

		JsonObject config = root.get(MITREidDataService.MITREID_CONNECT_1_3).getAsJsonObject();

		// make sure all the root elements are there
		assertThat(config.has(MITREidDataService.CLIENTS), is(true));
		assertThat(config.has(MITREidDataService.GRANTS), is(true));
		assertThat(config.has(MITREidDataService.WHITELISTEDSITES), is(true));
		assertThat(config.has(MITREidDataService.BLACKLISTEDSITES), is(true));
		assertThat(config.has(MITREidDataService.REFRESHTOKENS), is(true));
		assertThat(config.has(MITREidDataService.ACCESSTOKENS), is(true));
		assertThat(config.has(MITREidDataService.SYSTEMSCOPES), is(true));
		assertThat(config.has(MITREidDataService.AUTHENTICATIONHOLDERS), is(true));

		// make sure the root elements are all arrays
		assertThat(config.get(MITREidDataService.CLIENTS).isJsonArray(), is(true));
		assertThat(config.get(MITREidDataService.GRANTS).isJsonArray(), is(true));
		assertThat(config.get(MITREidDataService.WHITELISTEDSITES).isJsonArray(), is(true));
		assertThat(config.get(MITREidDataService.BLACKLISTEDSITES).isJsonArray(), is(true));
		assertThat(config.get(MITREidDataService.REFRESHTOKENS).isJsonArray(), is(true));
		assertThat(config.get(MITREidDataService.ACCESSTOKENS).isJsonArray(), is(true));
		assertThat(config.get(MITREidDataService.SYSTEMSCOPES).isJsonArray(), is(true));
		assertThat(config.get(MITREidDataService.AUTHENTICATIONHOLDERS).isJsonArray(), is(true));


		// check our client list (this test)
		JsonArray clients = config.get(MITREidDataService.CLIENTS).getAsJsonArray();

		assertThat(clients.size(), is(2));
		// check for both of our clients in turn
		Set<ClientDetailsEntity> checked = new HashSet<>();
		for (JsonElement e : clients) {
			assertThat(e.isJsonObject(), is(true));
			JsonObject client = e.getAsJsonObject();

			ClientDetailsEntity compare = null;
			if (client.get("clientId").getAsString().equals(client1.getClientId())) {
				compare = client1;
			} else if (client.get("clientId").getAsString().equals(client2.getClientId())) {
				compare = client2;
			}

			if (compare == null) {
				fail("Could not find matching clientId: " + client.get("clientId").getAsString());
			} else {
				assertThat(client.get("clientId").getAsString(), equalTo(compare.getClientId()));
				assertThat(client.get("secret").getAsString(), equalTo(compare.getClientSecret()));
				assertThat(client.get("accessTokenValiditySeconds").getAsInt(), equalTo(compare.getAccessTokenValiditySeconds()));
				assertThat(client.get("allowIntrospection").getAsBoolean(), equalTo(compare.isAllowIntrospection()));
				assertThat(jsonArrayToStringSet(client.get("redirectUris").getAsJsonArray()), equalTo(compare.getRedirectUris()));
				assertThat(jsonArrayToStringSet(client.get("scope").getAsJsonArray()), equalTo(compare.getScope()));
				assertThat(jsonArrayToStringSet(client.get("grantTypes").getAsJsonArray()), equalTo(compare.getGrantTypes()));
				assertThat((client.has("codeChallengeMethod") && !client.get("codeChallengeMethod").isJsonNull()) ? PKCEAlgorithm.parse(client.get("codeChallengeMethod").getAsString()) : null, equalTo(compare.getCodeChallengeMethod()));
				checked.add(compare);
			}
		}
		// make sure all of our clients were found
		assertThat(checked.containsAll(allClients), is(true));
	}