package com.tinesoft.droidlinguist.server.tools;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.ValidationEvent;
import javax.xml.validation.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.tinesoft.droidlinguist.server.exception.SourceStringsParserException;
import com.tinesoft.droidlinguist.server.json.translation.source.PluralItem;
import com.tinesoft.droidlinguist.server.json.translation.source.SourceItem;
import com.tinesoft.droidlinguist.server.json.translation.source.StringArrayItem;
import com.tinesoft.droidlinguist.server.json.translation.source.StringItem;
import com.tinesoft.droidlinguist.server.json.translation.source.StringItemType;
import com.tinesoft.droidlinguist.server.util.EagerValidationEventCollector;
import com.tinesoft.droidlinguist.server.util.JaxbUtil;
import com.tinesoft.droidlinguist.server.xmldom.ItemType;
import com.tinesoft.droidlinguist.server.xmldom.PluralsType;
import com.tinesoft.droidlinguist.server.xmldom.Resources;
import com.tinesoft.droidlinguist.server.xmldom.StringArrayType;
import com.tinesoft.droidlinguist.server.xmldom.StringType;
/**
* Component that parses the uploaded source strings xml file, into a list of
* {@link SourceItem} (i.e {@link StringItem}, {@link StringArrayItem} or
* {@link PluralItem}).
*
* @author Tine Kondo
*
*/
@Component
public class SourceStringsParser
{
private static final Logger LOG = LoggerFactory.getLogger(SourceStringsParser.class);
private static final String STRINGS_RESOURCES_XSD = "xsd/resources.xsd";
private JAXBContext jaxbContext;
private Schema validationSchema;
public List<SourceItem> parse(byte[] stringsXml) throws SourceStringsParserException
{
LOG.info("PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP");
LOG.info(" >>> Start parsing new source xml file...");
jaxbContext = JaxbUtil.createContextIfNull(Resources.class, jaxbContext);
validationSchema = JaxbUtil.createSchemaIfNull(STRINGS_RESOURCES_XSD, validationSchema);
EagerValidationEventCollector validationEventHandler = new EagerValidationEventCollector();
Resources resources = JaxbUtil.convertTo(stringsXml, jaxbContext, validationSchema, validationEventHandler);
// check if the xml contains (fatal) errors, and throw error
List<String> errors = checkForValidationErrors(validationEventHandler.getEvents());
if (!errors.isEmpty())
{
LOG.error(" !!! Source xml is not valid. Stop parsing.");
throw new SourceStringsParserException(errors);
}
List<SourceItem> strings = new ArrayList<>(resources.getStringOrStringArrayOrPlurals().size());
for (Object o : resources.getStringOrStringArrayOrPlurals())
{
// filling from the "<string>" element
if (o instanceof StringType)
{
StringType s = (StringType) o;
StringItem item = new StringItem();
item.setName(s.getName());
item.setType(StringItemType.STRING.getName());
item.setTranslatable(s.getTranslatable() == null ? true : s.getTranslatable());
item.setValue(JaxbUtil.getXmlMixedContentAsString(s.getContent()));
strings.add(item);
}
// filling from the "<string-array>" element
if (o instanceof StringArrayType)
{
StringArrayType s = (StringArrayType) o;
StringArrayItem item = new StringArrayItem();
item.setName(s.getName());
item.setType(StringItemType.STRING_ARRAY.getName());
item.setTranslatable(s.getTranslatable() == null ? true : s.getTranslatable());
item.setValue(new ArrayList<String>(s.getItem().size()));
for (ItemType i : s.getItem())
{
item.getValues().add(JaxbUtil.getXmlMixedContentAsString(i.getContent()));
}
strings.add(item);
}
// filling from the "<plurals>" element
if (o instanceof PluralsType)
{
PluralsType p = (PluralsType) o;
PluralItem item = new PluralItem();
item.setName(p.getName());
item.setType(StringItemType.PLURALS.getName());
item.setTranslatable(p.getTranslatable() == null ? true : p.getTranslatable());
item.setValue(new ArrayList<PluralItem.Value>(p.getItem().size()));
for (ItemType i : p.getItem())
{
PluralItem.Value v = new PluralItem.Value();
v.setQuantity(i.getQuantity().value());
v.setText(JaxbUtil.getXmlMixedContentAsString(i.getContent()));
item.getValues().add(v);
}
strings.add(item);
}
}
LOG.info(" <<< Done parsing source xml file.");
return strings;
}
private List<String> checkForValidationErrors(ValidationEvent... events)
{
List<String> errors = new ArrayList<>();
for (ValidationEvent event : events)
{
if (event.getSeverity() != ValidationEvent.WARNING)
{
String severity = (event.getSeverity() == ValidationEvent.ERROR) ? "[ERROR]: " : "[FATAL_ERROR]: ";
String location = JaxbUtil.getErrorLocation(event);
String message = String.format("%s %s Location: %s", severity, event.getMessage(), location);
errors.add(message);
}
}
return errors;
}
}