@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 testExportAccessTokens() throws IOException, ParseException {
		String expiration1 = "2014-09-10T22:49:44.090+00:00";
		Date expirationDate1 = formatter.parse(expiration1, Locale.ENGLISH);

		ClientDetailsEntity mockedClient1 = mock(ClientDetailsEntity.class);
		when(mockedClient1.getClientId()).thenReturn("mocked_client_1");

		AuthenticationHolderEntity mockedAuthHolder1 = mock(AuthenticationHolderEntity.class);
		when(mockedAuthHolder1.getId()).thenReturn(1L);

		OAuth2AccessTokenEntity token1 = new OAuth2AccessTokenEntity();
		token1.setId(1L);
		token1.setClient(mockedClient1);
		token1.setExpiration(expirationDate1);
		token1.setJwt(JWTParser.parse("eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0MTI3ODk5NjgsInN1YiI6IjkwMzQyLkFTREZKV0ZBIiwiYXRfaGFzaCI6InptTmt1QmNRSmNYQktNaVpFODZqY0EiLCJhdWQiOlsiY2xpZW50Il0sImlzcyI6Imh0dHA6XC9cL2xvY2FsaG9zdDo4MDgwXC9vcGVuaWQtY29ubmVjdC1zZXJ2ZXItd2ViYXBwXC8iLCJpYXQiOjE0MTI3ODkzNjh9.xkEJ9IMXpH7qybWXomfq9WOOlpGYnrvGPgey9UQ4GLzbQx7JC0XgJK83PmrmBZosvFPCmota7FzI_BtwoZLgAZfFiH6w3WIlxuogoH-TxmYbxEpTHoTsszZppkq9mNgOlArV4jrR9y3TPo4MovsH71dDhS_ck-CvAlJunHlqhs0"));
		token1.setAuthenticationHolder(mockedAuthHolder1);
		token1.setScope(ImmutableSet.of("id-token"));
		token1.setTokenType("Bearer");

		String expiration2 = "2015-01-07T18:31:50.079+00:00";
		Date expirationDate2 = formatter.parse(expiration2, Locale.ENGLISH);

		ClientDetailsEntity mockedClient2 = mock(ClientDetailsEntity.class);
		when(mockedClient2.getClientId()).thenReturn("mocked_client_2");

		AuthenticationHolderEntity mockedAuthHolder2 = mock(AuthenticationHolderEntity.class);
		when(mockedAuthHolder2.getId()).thenReturn(2L);

		OAuth2RefreshTokenEntity mockRefreshToken2 = mock(OAuth2RefreshTokenEntity.class);
		when(mockRefreshToken2.getId()).thenReturn(1L);

		OAuth2AccessTokenEntity token2 = new OAuth2AccessTokenEntity();
		token2.setId(2L);
		token2.setClient(mockedClient2);
		token2.setExpiration(expirationDate2);
		token2.setJwt(JWTParser.parse("eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0MTI3OTI5NjgsImF1ZCI6WyJjbGllbnQiXSwiaXNzIjoiaHR0cDpcL1wvbG9jYWxob3N0OjgwODBcL29wZW5pZC1jb25uZWN0LXNlcnZlci13ZWJhcHBcLyIsImp0aSI6IjBmZGE5ZmRiLTYyYzItNGIzZS05OTdiLWU0M2VhMDUwMzNiOSIsImlhdCI6MTQxMjc4OTM2OH0.xgaVpRLYE5MzbgXfE0tZt823tjAm6Oh3_kdR1P2I9jRLR6gnTlBQFlYi3Y_0pWNnZSerbAE8Tn6SJHZ9k-curVG0-ByKichV7CNvgsE5X_2wpEaUzejvKf8eZ-BammRY-ie6yxSkAarcUGMvGGOLbkFcz5CtrBpZhfd75J49BIQ"));
		token2.setAuthenticationHolder(mockedAuthHolder2);
		token2.setRefreshToken(mockRefreshToken2);
		token2.setScope(ImmutableSet.of("openid", "offline_access", "email", "profile"));
		token2.setTokenType("Bearer");

		Set<OAuth2AccessTokenEntity> allAccessTokens = ImmutableSet.of(token1, token2);

		Mockito.when(clientRepository.getAllClients()).thenReturn(new HashSet<ClientDetailsEntity>());
		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.getAllRefreshTokens()).thenReturn(new HashSet<OAuth2RefreshTokenEntity>());
		Mockito.when(tokenRepository.getAllAccessTokens()).thenReturn(allAccessTokens);
		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 access token list (this test)
		JsonArray accessTokens = config.get(MITREidDataService.ACCESSTOKENS).getAsJsonArray();

		assertThat(accessTokens.size(), is(2));
		// check for both of our access tokens in turn
		Set<OAuth2AccessTokenEntity> checked = new HashSet<>();
		for (JsonElement e : accessTokens) {
			assertTrue(e.isJsonObject());
			JsonObject token = e.getAsJsonObject();

			OAuth2AccessTokenEntity compare = null;
			if (token.get("id").getAsLong() == token1.getId().longValue()) {
				compare = token1;
			} else if (token.get("id").getAsLong() == token2.getId().longValue()) {
				compare = token2;
			}

			if (compare == null) {
				fail("Could not find matching id: " + token.get("id").getAsString());
			} else {
				assertThat(token.get("id").getAsLong(), equalTo(compare.getId()));
				assertThat(token.get("clientId").getAsString(), equalTo(compare.getClient().getClientId()));
				assertThat(token.get("expiration").getAsString(), equalTo(formatter.print(compare.getExpiration(), Locale.ENGLISH)));
				assertThat(token.get("value").getAsString(), equalTo(compare.getValue()));
				assertThat(token.get("type").getAsString(), equalTo(compare.getTokenType()));
				assertThat(token.get("authenticationHolderId").getAsLong(), equalTo(compare.getAuthenticationHolder().getId()));
				assertTrue(token.get("scope").isJsonArray());
				assertThat(jsonArrayToStringSet(token.getAsJsonArray("scope")), equalTo(compare.getScope()));
				if(token.get("refreshTokenId").isJsonNull()) {
					assertNull(compare.getRefreshToken());
				} else {
					assertThat(token.get("refreshTokenId").getAsLong(), equalTo(compare.getRefreshToken().getId()));
				}
				checked.add(compare);
			}
		}
		// make sure all of our access tokens were found
		assertThat(checked.containsAll(allAccessTokens), is(true));
	}