/**
* 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 JsonCollectionFormatParser.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 org.odata4j.core.OCollection;
import org.odata4j.core.OCollections;
import org.odata4j.core.OComplexObject;
import org.odata4j.core.OObject;
import org.odata4j.core.OSimpleObjects;
import org.odata4j.edm.EdmCollectionType;
import org.odata4j.edm.EdmComplexType;
import org.odata4j.edm.EdmDataServices;
import org.odata4j.edm.EdmSimpleType;
import org.odata4j.format.FormatParser;
import org.odata4j.format.Settings;
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.odata.DcJsonStreamReaderFactory.JsonStreamReader.JsonValueEvent;
import com.fujitsu.dc.core.utils.ODataUtils;
/**
* OCollectionのパーサー.
*/
public class DcJsonCollectionFormatParser extends DcJsonFormatParser implements
FormatParser<OCollection<? extends OObject>> {
private final EdmCollectionType returnType;
private String propertyName;
/**
* コンストラクタ.
* @param collectionType コレクションタイプ
* @param md スキーマ情報
* @param name プロパティ名
*/
public DcJsonCollectionFormatParser(EdmCollectionType collectionType, EdmDataServices md, String name) {
super(null);
super.setMetadata(md);
returnType = collectionType;
propertyName = name;
}
@Override
public OCollection<? extends OObject> parse(Reader reader) {
JsonStreamReader jsr = DcJsonStreamReaderFactory.createJsonStreamReader(reader);
try {
// parse the entry
OCollection<? extends OObject> o = parseCollection(jsr);
return o;
} finally {
jsr.close();
}
}
/**
* Collectionのパース.
* @param jsr JsonStreamReader
* @return OCollection
*/
protected OCollection<? extends OObject> parseCollection(JsonStreamReader jsr) {
ensureNext(jsr);
OCollection.Builder<OObject> c = newCollectionBuilder();
if (this.returnType.getItemType().isSimple()) {
// 配列の型がシンプル型の場合はOSimpleObjectとしてパースする
parseCollectionOfSimple(c, jsr);
} else {
// 配列の型がシンプル型でなければ、対応する型のパーサーを取得してComplexObjectとしてパースする
EdmComplexType ct = getMetadata().findEdmComplexType(
this.returnType.getItemType().getFullyQualifiedTypeName());
if (null != ct) {
// ComplexTypeが存在する場合は、パースを実施してComplexTypeObjectを取得する
Settings s = new Settings(getVersion(), getMetadata(),
getEntitySetName(), getEntityKey(), null, false, ct);
DcJsonComplexObjectFormatParser cofp = new DcJsonComplexObjectFormatParser(s);
while (jsr.hasNext()) {
OComplexObject obj = cofp.parseSingleObject(jsr);
if (null != obj) {
c = c.add(obj);
} else {
break;
}
}
} else {
// ComplexTypeがスキーマ定義上に存在しなければエラーとする
throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propertyName);
}
}
ensureEndArray(jsr.previousEvent());
return c.build();
}
/**
* シンプル型の配列に対するパース処理.
* @param builder OCollection.Builder
* @param jsr JsonStreamReader
*/
protected void parseCollectionOfSimple(OCollection.Builder<OObject> builder, JsonStreamReader jsr) {
while (jsr.hasNext()) {
JsonEvent e = jsr.nextEvent();
if (e.isValue()) {
JsonValueEvent ve = e.asValue();
String propValue = ve.getValue();
if (propValue != null) {
if (this.returnType.getItemType().equals(EdmSimpleType.BOOLEAN)
&& !ODataUtils.validateBoolean(propValue)) {
throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propertyName);
} else if (this.returnType.getItemType().equals(EdmSimpleType.SINGLE)
&& !ODataUtils.validateSingle(propValue)) {
throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propertyName);
} else if (this.returnType.getItemType().equals(EdmSimpleType.INT32)
&& !ODataUtils.validateInt32(propValue)) {
throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propertyName);
} else if (this.returnType.getItemType().equals(EdmSimpleType.DOUBLE)
&& !ODataUtils.validateDouble(propValue)) {
throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propertyName);
} else if (this.returnType.getItemType().equals(EdmSimpleType.STRING)
&& !ODataUtils.validateString(propValue)) {
throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propertyName);
} else if (this.returnType.getItemType().equals(EdmSimpleType.DATETIME)) {
if (!ODataUtils.validateDateTime(propValue)) {
throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(propertyName);
}
if (Common.SYSUTCDATETIME.equals(propValue)) {
String crrTime = String.valueOf(getCurrentTimeMillis());
propValue = String.format("/Date(%s)/", crrTime);
}
}
}
builder.add(OSimpleObjects.parse((EdmSimpleType<?>) this.returnType.getItemType(), propValue));
} else if (e.isEndArray()) {
break;
} else {
throw new RuntimeException("invalid JSON content");
}
}
}
/**
* コレクションビルダーを作成する.
* @return OCollection.Builder
*/
protected OCollection.Builder<OObject> newCollectionBuilder() {
return OCollections.<OObject>newBuilder(this.returnType.getItemType());
}
}