/** * personium.io * Modifications copyright 2014 FUJITSU LIMITED * * Licensed 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. * -------------------------------------------------- * This code is based on JsonComplexObjectFormatParser.java of odata4j-core, and some modifications * for personium.io are applied by us. * -------------------------------------------------- * The copyright and the license text of the original code is as follows: */ /**************************************************************************** * Copyright (c) 2010 odata4j * * Licensed 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 com.fujitsu.dc.core.odata; import java.io.Reader; import java.util.ArrayList; import java.util.List; import org.odata4j.core.OComplexObject; import org.odata4j.core.OComplexObjects; import org.odata4j.core.OProperties; import org.odata4j.core.OProperty; import org.odata4j.edm.EdmCollectionType; import org.odata4j.edm.EdmComplexType; import org.odata4j.edm.EdmProperty; import org.odata4j.edm.EdmProperty.CollectionKind; import org.odata4j.edm.EdmSimpleType; import org.odata4j.format.FormatParser; import org.odata4j.format.Settings; import org.odata4j.format.json.JsonStreamReaderFactory.JsonParseException; import org.odata4j.format.json.JsonTypeConverter; import com.fujitsu.dc.core.DcCoreException; import com.fujitsu.dc.core.model.ctl.Common; import com.fujitsu.dc.core.odata.DcJsonStreamReaderFactory.JsonStreamReader; import com.fujitsu.dc.core.odata.DcJsonStreamReaderFactory.JsonStreamReader.JsonEvent; import com.fujitsu.dc.core.utils.ODataUtils; /** * Parser for OComplexObjects in JSON. */ public class DcJsonComplexObjectFormatParser extends DcJsonFormatParser implements FormatParser<OComplexObject> { /** * コンストラクタ. * @param s 設定情報 */ public DcJsonComplexObjectFormatParser(Settings s) { super(s); if (s == null) { returnType = null; } else { returnType = (EdmComplexType) s.parseType; } } /** 返却する型. */ private EdmComplexType returnType = null; /** * ComplexTypeObjectのパース. * @param reader パース対象 * @return OComplexObject */ @Override public OComplexObject parse(Reader reader) { JsonStreamReader jsr = DcJsonStreamReaderFactory.createJsonStreamReader(reader); try { OComplexObject o = parseSingleObject(jsr); return o; } finally { jsr.close(); } } /** * ComplexTypeObjectのパース. * @param jsr パース対象文字のJsonStreamReader * @return OComplexObject */ public OComplexObject parseSingleObject(JsonStreamReader jsr) { ensureNext(jsr); JsonEvent event = jsr.nextEvent(); if (event.isStartObject()) { List<OProperty<?>> props = new ArrayList<OProperty<?>>(); return eatProps(props, jsr); } else { // not a start object. return null; } } /** * ComplexTypeObjectのパース. * @param jsr パース対象文字のJsonStreamReader * @param startPropertyEvent JsonEvent * @return OComplexObject */ public OComplexObject parseSingleObject(JsonStreamReader jsr, JsonEvent startPropertyEvent) { List<OProperty<?>> props = new ArrayList<OProperty<?>>(); addProperty(props, startPropertyEvent.asStartProperty().getName(), jsr); return eatProps(props, jsr); } /** * 不足分のComplexTypePropertyを追加する. * @param props 追加対象Propertyリスト * @param jsr パース対象文字のJsonStreamReader * @return OComplexObject */ private OComplexObject eatProps(List<OProperty<?>> props, JsonStreamReader jsr) { ensureNext(jsr); while (jsr.hasNext()) { JsonEvent event = jsr.nextEvent(); if (event.isStartProperty()) { addProperty(props, event.asStartProperty().getName(), jsr); } else if (event.isEndProperty()) { continue; } else if (event.isEndObject()) { break; } else { throw new JsonParseException("unexpected parse event: " + event.toString()); } } return OComplexObjects.create(returnType, props); } /** * プロパティの追加. * @param props 追加対象Propertyリスト * @param name 追加Property名 * @param jsr パース対象文字のJsonStreamReader */ protected void addProperty(List<OProperty<?>> props, String name, JsonStreamReader jsr) { JsonEvent event = jsr.nextEvent(); // ComplexType定義からプロパティ定義を取得する EdmProperty ep = returnType.findProperty(name); if (event.isEndProperty()) { if (ep == null) { // プロパティ定義がComplexType定義上に存在しなければエラーとする throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } if (ep.getType().isSimple()) { // 値チェック String propValue = event.asEndProperty().getValue(); if (propValue != null) { if (ep.getType().equals(EdmSimpleType.BOOLEAN) && !ODataUtils.validateBoolean(propValue)) { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } else if (ep.getType().equals(EdmSimpleType.SINGLE) && !ODataUtils.validateSingle(propValue)) { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } else if (ep.getType().equals(EdmSimpleType.INT32) && !ODataUtils.validateInt32(propValue)) { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } else if (ep.getType().equals(EdmSimpleType.DOUBLE) && !ODataUtils.validateDouble(propValue)) { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } else if (ep.getType().equals(EdmSimpleType.STRING) && !ODataUtils.validateString(propValue)) { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } else if (ep.getType().equals(EdmSimpleType.DATETIME)) { if (!ODataUtils.validateDateTime(propValue)) { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } if (Common.SYSUTCDATETIME.equals(propValue)) { String crrTime = String.valueOf(getCurrentTimeMillis()); propValue = String.format("/Date(%s)/", crrTime); } } } // シンプル型(文字列や数値など)であればプロパティに追加する props.add(JsonTypeConverter.parse(name, (EdmSimpleType<?>) ep.getType(), propValue)); } else { // ComplexType型であれば再度パースを実施して、プロパティに追加する JsonObjectPropertyValue val = getValue(event, name, jsr, ep); if (val != null) { props.add(OProperties.complex(name, (EdmComplexType) val.complexObject.getType(), val.complexObject.getProperties())); } else { // ComplexTypeの値がNullの場合 EdmComplexType ct = getMetadata().findEdmComplexType(ep.getType().getFullyQualifiedTypeName()); props.add(OProperties.complex(name, ct, null)); } } } else if (event.isStartObject()) { JsonObjectPropertyValue val = getValue(event, name, jsr, ep); if (val.complexObject != null) { // ComplexTypeデータであればプロパティに追加する props.add(OProperties.complex(name, (EdmComplexType) val.complexObject.getType(), val.complexObject.getProperties())); } else { // ComplexTypeデータ以外はエラーとする throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } } else if (event.isStartArray()) { // 配列オブジェクトの場合 JsonObjectPropertyValue val = new JsonObjectPropertyValue(); // スキーマ定義が存在してCollectionKindがNoneでなければ、配列としてパースする if (null != ep && ep.getCollectionKind() != CollectionKind.NONE) { val.collectionType = new EdmCollectionType(ep.getCollectionKind(), ep.getType()); DcJsonCollectionFormatParser cfp = new DcJsonCollectionFormatParser(val.collectionType, getMetadata(), name); val.collection = cfp.parseCollection(jsr); } // パースに成功した場合は、プロパティに追加する if (val.collectionType != null && val.collection != null) { props.add(OProperties.collection(name, val.collectionType, val.collection)); } else { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } } else { throw new JsonParseException("expecting endproperty, got: " + event.toString()); } } /** * JSONオブジェクトの値を取得する. * @param event JsonEvent * @param name プロパティ名 * @param jsr JsonStreamReader * @param ep プロパティ定義 * @return JsonObjectPropertyValue */ protected JsonObjectPropertyValue getValue(JsonEvent event, String name, JsonStreamReader jsr, EdmProperty ep) { JsonObjectPropertyValue rt = new JsonObjectPropertyValue(); if (event.isStartObject()) { // ensureStartObject(value); event = jsr.nextEvent(); ensureStartProperty(event); // スキーマ定義からComplexType定義を取得する EdmComplexType ct = getMetadata().findEdmComplexType(ep.getType().getFullyQualifiedTypeName()); if (null != ct) { // ComplexTypeが存在する場合は、パースを実施してComplexTypeObjectを取得する Settings s = new Settings(getVersion(), getMetadata(), null, null, null, false, ct); DcJsonComplexObjectFormatParser cofp = new DcJsonComplexObjectFormatParser(s); rt.complexObject = cofp.parseSingleObject(jsr, event); } else { // ComplexTypeがスキーマ定義上に存在しなければエラーとする throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } ensureEndProperty(jsr.nextEvent()); } else if (event.isEndProperty() && event.asEndProperty().getValue() == null) { // ComplexTypeの値がNullの場合 return null; } else { throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name); } return rt; } }