1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.statementservice.retriever; 18 19 import android.util.JsonReader; 20 21 import org.json.JSONArray; 22 import org.json.JSONException; 23 import org.json.JSONObject; 24 25 import java.io.IOException; 26 import java.io.StringReader; 27 import java.util.ArrayList; 28 import java.util.List; 29 30 /** 31 * Utility class that parses JSON-formatted statements. 32 */ 33 /* package private */ final class StatementParser { 34 35 private static final String FIELD_NOT_STRING_FORMAT_STRING = "Expected %s to be string."; 36 private static final String FIELD_NOT_ARRAY_FORMAT_STRING = "Expected %s to be array."; 37 38 /** 39 * Parses a JSON array of statements. 40 */ parseStatementList(String statementList, AbstractAsset source)41 static ParsedStatement parseStatementList(String statementList, AbstractAsset source) 42 throws JSONException, IOException { 43 List<Statement> statements = new ArrayList<Statement>(); 44 List<String> delegates = new ArrayList<String>(); 45 46 JsonReader reader = new JsonReader(new StringReader(statementList)); 47 reader.setLenient(false); 48 49 reader.beginArray(); 50 while (reader.hasNext()) { 51 ParsedStatement result; 52 try { 53 result = parseStatement(reader, source); 54 } catch (AssociationServiceException e) { 55 // The element in the array is well formatted Json but not a well-formed Statement. 56 continue; 57 } 58 statements.addAll(result.getStatements()); 59 delegates.addAll(result.getDelegates()); 60 } 61 reader.endArray(); 62 63 return new ParsedStatement(statements, delegates); 64 } 65 66 /** 67 * Parses a single JSON statement. 68 */ parseStatement(String statementString, AbstractAsset source)69 static ParsedStatement parseStatement(String statementString, AbstractAsset source) 70 throws AssociationServiceException, IOException, JSONException { 71 JsonReader reader = new JsonReader(new StringReader(statementString)); 72 reader.setLenient(false); 73 return parseStatement(reader, source); 74 } 75 76 /** 77 * Parses a single JSON statement. This method guarantees that exactly one JSON object 78 * will be consumed. 79 */ parseStatement(JsonReader reader, AbstractAsset source)80 static ParsedStatement parseStatement(JsonReader reader, AbstractAsset source) 81 throws JSONException, AssociationServiceException, IOException { 82 List<Statement> statements = new ArrayList<Statement>(); 83 List<String> delegates = new ArrayList<String>(); 84 85 JSONObject statement = JsonParser.parse(reader); 86 87 if (statement.optString(Utils.DELEGATE_FIELD_DELEGATE, null) != null) { 88 delegates.add(statement.optString(Utils.DELEGATE_FIELD_DELEGATE)); 89 } else { 90 JSONObject targetObject = statement.optJSONObject(Utils.ASSET_DESCRIPTOR_FIELD_TARGET); 91 if (targetObject == null) { 92 throw new AssociationServiceException(String.format( 93 FIELD_NOT_STRING_FORMAT_STRING, Utils.ASSET_DESCRIPTOR_FIELD_TARGET)); 94 } 95 96 JSONArray relations = statement.optJSONArray(Utils.ASSET_DESCRIPTOR_FIELD_RELATION); 97 if (relations == null) { 98 throw new AssociationServiceException(String.format( 99 FIELD_NOT_ARRAY_FORMAT_STRING, Utils.ASSET_DESCRIPTOR_FIELD_RELATION)); 100 } 101 102 AbstractAsset target = AssetFactory.create(targetObject); 103 for (int i = 0; i < relations.length(); i++) { 104 statements.add(Statement 105 .create(source, target, Relation.create(relations.getString(i)))); 106 } 107 } 108 109 return new ParsedStatement(statements, delegates); 110 } 111 } 112