/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.stanbol.enhancer.nlp.json.valuetype.impl;
import java.util.EnumSet;
import java.util.List;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.stanbol.enhancer.nlp.json.JsonUtils;
import org.apache.stanbol.enhancer.nlp.json.valuetype.ValueTypeParser;
import org.apache.stanbol.enhancer.nlp.json.valuetype.ValueTypeParserRegistry;
import org.apache.stanbol.enhancer.nlp.json.valuetype.ValueTypeSerializer;
import org.apache.stanbol.enhancer.nlp.json.valuetype.ValueTypeSerializerRegistry;
import org.apache.stanbol.enhancer.nlp.morpho.Case;
import org.apache.stanbol.enhancer.nlp.morpho.CaseTag;
import org.apache.stanbol.enhancer.nlp.morpho.Definitness;
import org.apache.stanbol.enhancer.nlp.morpho.Gender;
import org.apache.stanbol.enhancer.nlp.morpho.GenderTag;
import org.apache.stanbol.enhancer.nlp.morpho.MorphoFeatures;
import org.apache.stanbol.enhancer.nlp.morpho.NumberFeature;
import org.apache.stanbol.enhancer.nlp.morpho.NumberTag;
import org.apache.stanbol.enhancer.nlp.morpho.Person;
import org.apache.stanbol.enhancer.nlp.morpho.Tense;
import org.apache.stanbol.enhancer.nlp.morpho.TenseTag;
import org.apache.stanbol.enhancer.nlp.morpho.VerbMood;
import org.apache.stanbol.enhancer.nlp.morpho.VerbMoodTag;
import org.apache.stanbol.enhancer.nlp.pos.PosTag;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(immediate=true,policy=ConfigurationPolicy.IGNORE)
@Service(value={ValueTypeParser.class,ValueTypeSerializer.class})
@Property(name=ValueTypeParser.PROPERTY_TYPE, value=MorphoFeaturesSupport.TYPE_VALUE)
public class MorphoFeaturesSupport implements ValueTypeParser<MorphoFeatures>, ValueTypeSerializer<MorphoFeatures> {
private final Logger log = LoggerFactory.getLogger(MorphoFeaturesSupport.class);
public static final String TYPE_VALUE = "org.apache.stanbol.enhancer.nlp.morpho.MorphoFeatures";
@Reference
protected ValueTypeSerializerRegistry serializerRegistry;
@Reference
protected ValueTypeParserRegistry parserRegistry;
protected ValueTypeSerializer<PosTag> getPosTagSerializer(){
if(serializerRegistry == null){
serializerRegistry = ValueTypeSerializerRegistry.getInstance();
}
return serializerRegistry.getSerializer(PosTag.class);
}
protected ValueTypeParser<PosTag> getPosTagParser(){
if(parserRegistry == null){
parserRegistry = ValueTypeParserRegistry.getInstance();
}
return parserRegistry.getParser(PosTag.class);
}
@Override
public Class<MorphoFeatures> getType() {
return MorphoFeatures.class;
}
@Override
public ObjectNode serialize(ObjectMapper mapper, MorphoFeatures morpho){
ObjectNode jMorpho = mapper.createObjectNode();
jMorpho.put("lemma", morpho.getLemma());
List<CaseTag> caseList = morpho.getCaseList();
if(!caseList.isEmpty()){
ArrayNode jCases = mapper.createArrayNode();
for(CaseTag caseTag : caseList){
ObjectNode jCase = mapper.createObjectNode();
jCase.put("tag", caseTag.getTag());
if(caseTag.getCase() != null){
jCase.put("type", caseTag.getCase().name());
}
jCases.add(jCase);
}
jMorpho.put("case", jCases);
}
List<Definitness> definitnesses = morpho.getDefinitnessList();
if(!definitnesses.isEmpty()){
if(definitnesses.size() == 1){
jMorpho.put("definitness",definitnesses.get(0).name());
} else {
ArrayNode jDefinitnesses = mapper.createArrayNode();
for(Definitness d : definitnesses){
jDefinitnesses.add(d.name());
}
jMorpho.put("definitness", jDefinitnesses);
}
}
List<GenderTag> genderList = morpho.getGenderList();
if(!genderList.isEmpty()){
ArrayNode jGenders = mapper.createArrayNode();
for(GenderTag genderTag : genderList){
ObjectNode jGender = mapper.createObjectNode();
jGender.put("tag", genderTag.getTag());
if(genderTag.getGender() != null){
jGender.put("type", genderTag.getGender().name());
}
jGenders.add(jGender);
}
jMorpho.put("gender", jGenders);
}
List<NumberTag> numberList = morpho.getNumberList();
if(!numberList.isEmpty()){
ArrayNode jNumbers = mapper.createArrayNode();
for(NumberTag numberTag : numberList){
ObjectNode jNumber = mapper.createObjectNode();
jNumber.put("tag", numberTag.getTag());
if(numberTag.getNumber() != null){
jNumber.put("type", numberTag.getNumber().name());
}
jNumbers.add(jNumber);
}
jMorpho.put("number", jNumbers);
}
List<Person> persons = morpho.getPersonList();
if(!persons.isEmpty()){
if(persons.size() == 1){
jMorpho.put("person",persons.get(0).name());
} else {
ArrayNode jPersons = mapper.createArrayNode();
for(Person d : persons){
jPersons.add(d.name());
}
jMorpho.put("person", jPersons);
}
}
List<PosTag> posList = morpho.getPosList();
if(!posList.isEmpty()){
ArrayNode jPosTags = mapper.createArrayNode();
for(PosTag posTag : posList){
jPosTags.add(getPosTagSerializer().serialize(mapper,posTag));
}
jMorpho.put("pos", jPosTags);
}
List<TenseTag> tenseList = morpho.getTenseList();
if(!tenseList.isEmpty()){
ArrayNode jTenses = mapper.createArrayNode();
for(TenseTag tenseTag : tenseList){
ObjectNode jTense = mapper.createObjectNode();
jTense.put("tag", tenseTag.getTag());
if(tenseTag.getTense() != null){
jTense.put("type", tenseTag.getTense().name());
}
jTenses.add(jTense);
}
jMorpho.put("tense", jTenses);
}
List<VerbMoodTag> verbMoodList = morpho.getVerbMoodList();
if(!verbMoodList.isEmpty()){
ArrayNode jMoods = mapper.createArrayNode();
for(VerbMoodTag verbMoodTag : verbMoodList){
ObjectNode jMood = mapper.createObjectNode();
jMood.put("tag", verbMoodTag.getTag());
if(verbMoodTag.getVerbForm() != null){
jMood.put("type", verbMoodTag.getVerbForm().name());
}
jMoods.add(jMood);
}
jMorpho.put("verb-mood", jMoods);
}
return jMorpho;
}
@Override
public MorphoFeatures parse(ObjectNode jMorpho) {
JsonNode jLemma = jMorpho.path("lemma");
if(!jLemma.isTextual()){
throw new IllegalStateException("Field 'lemma' MUST provide a String value (parsed JSON: "
+jMorpho);
}
MorphoFeatures morpho = new MorphoFeatures(jLemma.asText());
JsonNode node = jMorpho.path("case");
if(node.isArray()){
ArrayNode jCases = (ArrayNode)node;
for(int i=0;i<jCases.size();i++){
JsonNode member = jCases.get(i);
if(member.isObject()){
ObjectNode jCase = (ObjectNode)member;
JsonNode tag = jCase.path("tag");
if(tag.isTextual()){
EnumSet<Case> type = JsonUtils.parseEnum(jCase, "type", Case.class);
if(type.isEmpty()){
morpho.addCase(new CaseTag(tag.getTextValue()));
} else {
morpho.addCase(new CaseTag(tag.getTextValue(),type.iterator().next()));
}
} else {
log.warn("Unable to parse CaseTag becuase 'tag' value is "
+ "missing or is not a String (json: "+jCase.toString()+")");
}
} else {
log.warn("Unable to parse CaseTag from "+member.toString());
}
}
} else if(!node.isMissingNode()) {
log.warn("Unable to parse CaseTags (Json Array expected as value for field 'case' but was "
+ node);
}
if(jMorpho.has("definitness")){
for(Definitness d : JsonUtils.parseEnum(jMorpho, "definitness", Definitness.class)){
morpho.addDefinitness(d);
}
}
node = jMorpho.path("gender");
if(node.isArray()){
ArrayNode jGenders = (ArrayNode)node;
for(int i=0;i<jGenders.size();i++){
JsonNode member = jGenders.get(i);
if(member.isObject()){
ObjectNode jGender = (ObjectNode)member;
JsonNode tag = jGender.path("tag");
if(tag.isTextual()){
EnumSet<Gender> type = JsonUtils.parseEnum(jGender, "type", Gender.class);
if(type.isEmpty()){
morpho.addGender(new GenderTag(tag.getTextValue()));
} else {
morpho.addGender(new GenderTag(tag.getTextValue(),type.iterator().next()));
}
} else {
log.warn("Unable to parse GenderTag becuase 'tag' value is "
+ "missing or is not a String (json: "+jGender.toString()+")");
}
} else {
log.warn("Unable to parse GenderTag from "+member.toString());
}
}
} else if(!node.isMissingNode()) {
log.warn("Unable to parse GenderTag (Json Array expected as value for field 'case' but was "
+ node);
}
node = jMorpho.path("number");
if(node.isArray()){
ArrayNode jNumbers = (ArrayNode)node;
for(int i=0;i<jNumbers.size();i++){
JsonNode member = jNumbers.get(i);
if(member.isObject()){
ObjectNode jNumber = (ObjectNode)member;
JsonNode tag = jNumber.path("tag");
if(tag.isTextual()){
EnumSet<NumberFeature> type = JsonUtils.parseEnum(jNumber, "type", NumberFeature.class);
if(type.isEmpty()){
morpho.addNumber(new NumberTag(tag.getTextValue()));
} else {
morpho.addNumber(new NumberTag(tag.getTextValue(),type.iterator().next()));
}
} else {
log.warn("Unable to parse NumberTag becuase 'tag' value is "
+ "missing or is not a String (json: "+jNumber.toString()+")");
}
} else {
log.warn("Unable to parse NumberTag from "+member.toString());
}
}
} else if(!node.isMissingNode()) {
log.warn("Unable to parse NumberTag (Json Array expected as value for field 'case' but was "
+ node);
}
if(jMorpho.has("person")){
for(Person p : JsonUtils.parseEnum(jMorpho, "person", Person.class)){
morpho.addPerson(p);
}
}
node = jMorpho.path("pos");
if(node.isArray()){
ArrayNode jPosTags = (ArrayNode)node;
for(int i=0;i<jPosTags.size();i++){
JsonNode member = jPosTags.get(i);
if(member.isObject()){
ObjectNode jPosTag = (ObjectNode)member;
morpho.addPos(getPosTagParser().parse(jPosTag));
} else {
log.warn("Unable to parse PosTag from "+member.toString());
}
}
} else if(!node.isMissingNode()){
log.warn("Unable to parse PosTag (Json Array expected as value for field 'case' but was "
+ node);
}
node = jMorpho.path("tense");
if(node.isArray()){
ArrayNode jTenses = (ArrayNode)node;
for(int i=0;i<jTenses.size();i++){
JsonNode member = jTenses.get(i);
if(member.isObject()){
ObjectNode jTense = (ObjectNode)member;
JsonNode tag = jTense.path("tag");
if(tag.isTextual()){
EnumSet<Tense> type = JsonUtils.parseEnum(jTense, "type", Tense.class);
if(type.isEmpty()){
morpho.addTense(new TenseTag(tag.getTextValue()));
} else {
morpho.addTense(new TenseTag(tag.getTextValue(),type.iterator().next()));
}
} else {
log.warn("Unable to parse TenseTag becuase 'tag' value is "
+ "missing or is not a String (json: "+jTense.toString()+")");
}
} else {
log.warn("Unable to parse TenseTag from "+member.toString());
}
}
} else if(!node.isMissingNode()) {
log.warn("Unable to parse TenseTag (Json Array expected as value for field 'case' but was "
+ node);
}
node = jMorpho.path("verb-mood");
if(node.isArray()){
ArrayNode jVerbMoods = (ArrayNode)node;
for(int i=0;i<jVerbMoods.size();i++){
JsonNode member = jVerbMoods.get(i);
if(member.isObject()){
ObjectNode jVerbMood = (ObjectNode)member;
JsonNode tag = jVerbMood.path("tag");
if(tag.isTextual()){
EnumSet<VerbMood> type = JsonUtils.parseEnum(jVerbMood, "type", VerbMood.class);
if(type.isEmpty()){
morpho.addVerbForm(new VerbMoodTag(tag.getTextValue()));
} else {
morpho.addVerbForm(new VerbMoodTag(tag.getTextValue(),type.iterator().next()));
}
} else {
log.warn("Unable to parse VerbMoodTag becuase 'tag' value is "
+ "missing or is not a String (json: "+jVerbMood.toString()+")");
}
} else {
log.warn("Unable to parse VerbMoodTag from "+member.toString());
}
}
} else if(!node.isMissingNode()) {
log.warn("Unable to parse VerbMoodTag (Json Array expected as value for field 'case' but was "
+ node);
}
return morpho;
}
}