/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.ims.qti21.model.xml;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import org.olat.imscp.xml.manifest.ManifestMetadataType;
import org.olat.imscp.xml.manifest.MetadataType;
import org.olat.imsmd.xml.manifest.ClassificationType;
import org.olat.imsmd.xml.manifest.ContextType;
import org.olat.imsmd.xml.manifest.CopyrightandotherrestrictionsType;
import org.olat.imsmd.xml.manifest.CoverageType;
import org.olat.imsmd.xml.manifest.DescriptionType;
import org.olat.imsmd.xml.manifest.EducationalType;
import org.olat.imsmd.xml.manifest.EntryType;
import org.olat.imsmd.xml.manifest.GeneralType;
import org.olat.imsmd.xml.manifest.KeywordType;
import org.olat.imsmd.xml.manifest.LangstringType;
import org.olat.imsmd.xml.manifest.LifecycleType;
import org.olat.imsmd.xml.manifest.LomType;
import org.olat.imsmd.xml.manifest.PurposeType;
import org.olat.imsmd.xml.manifest.RightsType;
import org.olat.imsmd.xml.manifest.SourceType;
import org.olat.imsmd.xml.manifest.StringType;
import org.olat.imsmd.xml.manifest.TaxonType;
import org.olat.imsmd.xml.manifest.TaxonpathType;
import org.olat.imsmd.xml.manifest.TechnicalType;
import org.olat.imsmd.xml.manifest.TitleType;
import org.olat.imsmd.xml.manifest.TypicallearningtimeType;
import org.olat.imsmd.xml.manifest.ValueType;
import org.olat.imsmd.xml.manifest.VersionType;
import org.olat.imsqti.xml.manifest.QTIMetadataType;
import org.olat.oo.xml.manifest.OpenOLATMetadataType;
/**
*
* Initial date: 23.02.2016<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class ManifestMetadataBuilder {
protected static final org.olat.oo.xml.manifest.ObjectFactory ooObjectFactory = new org.olat.oo.xml.manifest.ObjectFactory();
protected static final org.olat.imscp.xml.manifest.ObjectFactory cpObjectFactory = new org.olat.imscp.xml.manifest.ObjectFactory();
protected static final org.olat.imsmd.xml.manifest.ObjectFactory mdObjectFactory = new org.olat.imsmd.xml.manifest.ObjectFactory();
protected static final org.olat.imsqti.xml.manifest.ObjectFactory qtiObjectFactory = new org.olat.imsqti.xml.manifest.ObjectFactory();
public static final String ASSESSMENTTEST_MIMETYPE = "text/x-imsqti-test-xml";
public static final String ASSESSMENTITEM_MIMETYPE = "text/x-imsqti-item-xml";
private MetadataType metadata;
private ManifestMetadataType manifestMetadata;
public ManifestMetadataBuilder() {
metadata = cpObjectFactory.createMetadataType();
}
public ManifestMetadataBuilder(MetadataType metadata) {
this.metadata = metadata;
}
public MetadataType getMetadata() {
return metadata;
}
public void setMetadata(MetadataType metadata) {
this.metadata = metadata;
}
public String getTitle() {
GeneralType general = getGeneral(false);
if(general != null) {
TitleType type = getFromAny(TitleType.class, general.getContent());
return type == null ? null : getFirstString(type.getLangstring());
}
return null;
}
public void setTitle(String title, String lang) {
GeneralType general = getGeneral(true);
if(general != null) {
TitleType type = getFromAny(TitleType.class, general.getContent());
if(type == null) {
type = mdObjectFactory.createTitleType();
general.getContent().add(mdObjectFactory.createTitle(type));
}
createOrUpdateFirstLangstring(type.getLangstring(), title, lang);
}
}
public String getDescription() {
GeneralType general = getGeneral(false);
if(general != null) {
DescriptionType type = getFromAny(DescriptionType.class, general.getContent());
return type == null ? null : getFirstString(type.getLangstring());
}
return null;
}
public void setDescription(String description, String lang) {
GeneralType general = getGeneral(true);
if(general != null) {
DescriptionType type = getFromAny(DescriptionType.class, general.getContent());
if(type == null) {
type = mdObjectFactory.createDescriptionType();
general.getContent().add(mdObjectFactory.createDescription(type));
}
createOrUpdateFirstLangstring(type.getLangstring(), description, lang);
}
}
public String getGeneralKeywords() {
GeneralType general = getGeneral(false);
if(general != null) {
StringBuilder keywords = new StringBuilder();
for(Object any:general.getContent()) {
if(any instanceof JAXBElement<?>
&& ((JAXBElement<?>)any).getValue().getClass().equals(KeywordType.class)) {
KeywordType keywordType = (KeywordType)((JAXBElement<?>)any).getValue();
List<LangstringType> langStrings = keywordType.getLangstring();
for(LangstringType langString:langStrings) {
String keyword = langString.getValue();
if(keywords.length() > 0) keywords.append(" ");
keywords.append(keyword);
}
}
}
return keywords.toString();
}
return null;
}
public void setGeneralKeywords(String keywords, String lang) {
GeneralType general = getGeneral(true);
if(general != null) {
clearFromAny(KeywordType.class, general.getContent());
for(StringTokenizer tokenizer = new StringTokenizer(keywords, " "); tokenizer.hasMoreTokens(); ) {
String keyword = tokenizer.nextToken();
KeywordType type = mdObjectFactory.createKeywordType();
general.getContent().add(mdObjectFactory.createKeyword(type));
createOrUpdateFirstLangstring(type.getLangstring(), keyword, lang);
}
}
}
public void setLanguage(String language, String lang) {
GeneralType general = getGeneral(true);
if(general != null) {
StringType type = getFromAny(StringType.class, general.getContent());
if(type == null) {
type = mdObjectFactory.createStringType();
QName languageQNAME = new QName("http://www.imsglobal.org/xsd/imsmd_v1p2", "context");
JAXBElement<StringType> typeEl = new JAXBElement<StringType>(languageQNAME, StringType.class, null, type);
general.getContent().add(typeEl);
}
type.setLang(lang);
type.setValue(language);
}
}
public void setCoverage(String coverage, String lang) {
GeneralType general = getGeneral(true);
if(general != null) {
CoverageType type = getFromAny(CoverageType.class, general.getContent());
if(type == null) {
type = mdObjectFactory.createCoverageType();
general.getContent().add(mdObjectFactory.createCoverage(type));
}
createOrUpdateFirstLangstring(type.getLangstring(), coverage, lang);
}
}
public void setTechnicalFormat(String... formats) {
if(formats != null && formats.length > 0 && formats[0] != null) {
TechnicalType technical = getTechnical(true);
clearFromAny("format", technical.getContent());
for(int i=0; i<formats.length; i++) {
technical.getContent().add(mdObjectFactory.createFormat(formats[i]));
}
}
}
public void setEducationalContext(String context, String lang) {
EducationalType educational = getEducational(true);
if(educational != null) {
ContextType type = getFromAny(ContextType.class, educational.getContent());
if(type == null) {
type = mdObjectFactory.createContextType();
educational.getContent().add(mdObjectFactory.createContext(type));
}
SourceType sourceType = mdObjectFactory.createSourceType();
sourceType.setLangstring(createString("https://www.openolat.org", lang));
ValueType valueType = mdObjectFactory.createValueType();
valueType.setLangstring(createString(context, lang));
type.setSource(sourceType);
type.setValue(valueType);
}
}
public void setEducationalLearningTime(String datetime) {
EducationalType educational = getEducational(true);
if(educational != null) {
TypicallearningtimeType type = getFromAny(TypicallearningtimeType.class, educational.getContent());
if(type == null) {
type = mdObjectFactory.createTypicallearningtimeType();
educational.getContent().add(mdObjectFactory.createTypicallearningtime(type));
}
type.setDatetime(datetime);
}
}
public void setLicense(String license) {
RightsType rights = getRights(true);
if(rights != null) {
CopyrightandotherrestrictionsType type = getFromAny(CopyrightandotherrestrictionsType.class, rights.getContent());
if(type == null) {
type = mdObjectFactory.createCopyrightandotherrestrictionsType();
rights.getContent().add(mdObjectFactory.createCopyrightandotherrestrictions(type));
}
SourceType sourceType = mdObjectFactory.createSourceType();
sourceType.setLangstring(createString("https://www.openolat.org", "en"));
ValueType valueType = mdObjectFactory.createValueType();
valueType.setLangstring(createString(license, "en"));
type.setSource(sourceType);
type.setValue(valueType);
}
}
/**
* Set a taxonomy path of purpose "discipline"
* @param taxonomyPath
* @param lang
*/
public void setClassificationTaxonomy(String taxonomyPath, String lang) {
ClassificationType classification = getClassification("discipline", lang, true);
if(classification != null) {
TaxonpathType taxonpathType = mdObjectFactory.createTaxonpathType();
clearFromAny(TaxonpathType.class, classification.getContent());
classification.getContent().add(mdObjectFactory.createTaxonpath(taxonpathType));
taxonpathType.getTaxon().clear();
SourceType sourceType = mdObjectFactory.createSourceType();
sourceType.setLangstring(createString("Unkown", "en"));
taxonpathType.setSource(sourceType);
for(StringTokenizer tokenizer = new StringTokenizer(taxonomyPath, "/"); tokenizer.hasMoreTokens(); ) {
String level = tokenizer.nextToken();
TaxonType taxonType = mdObjectFactory.createTaxonType();
EntryType entryType = mdObjectFactory.createEntryType();
createOrUpdateFirstLangstring(entryType.getLangstring(), level, lang);
taxonType.setEntry(entryType);
taxonpathType.getTaxon().add(taxonType);
}
}
}
public void createOrUpdateFirstLangstring(List<LangstringType> langStrings, String value, String lang) {
if(langStrings.isEmpty()) {
langStrings.add(createString(value, lang));
} else {
langStrings.get(0).setValue(value);
langStrings.get(0).setLang(lang);
}
}
public LangstringType createString(String value, String lang) {
LangstringType string = mdObjectFactory.createLangstringType();
string.setLang(lang);
string.setValue(value);
return string;
}
public SourceType createSource(String value, String lang) {
SourceType sourceType = mdObjectFactory.createSourceType();
sourceType.setLangstring(createString(value, lang));
return sourceType;
}
public ValueType createValue(String value, String lang) {
ValueType valueType = mdObjectFactory.createValueType();
valueType.setLangstring(createString(value, lang));
return valueType;
}
public String getFirstString(List<LangstringType> langStrings) {
String firstString = null;
if(langStrings != null && langStrings.size() > 0) {
firstString = langStrings.get(0).getValue();
}
return firstString;
}
public RightsType getRights(boolean create) {
LomType lom = getLom(create);
if(lom == null) return null;
RightsType rights = lom.getRights();
if(rights == null && create) {
rights = mdObjectFactory.createRightsType();
lom.setRights(rights);
}
return rights;
}
public ClassificationType getClassification(String purpose, String lang, boolean create) {
LomType lom = getLom(create);
if(lom == null) return null;
ClassificationType classification = null;
List<ClassificationType> classifications = lom.getClassification();
for(ClassificationType cl:classifications) {
PurposeType purposeType = getFromAny(PurposeType.class, cl.getContent());
if(purposeType != null && purposeType.getValue() != null && purposeType.getValue().getLangstring() != null) {
String value = purposeType.getValue().getLangstring().getValue();
if(value != null && value.equals(purpose)) {
classification = cl;
break;
}
}
}
if(classification == null && create) {
classification = mdObjectFactory.createClassificationType();
PurposeType purposeType = mdObjectFactory.createPurposeType();
purposeType.setSource(createSource("LOMv1.0", lang));
purposeType.setValue(createValue(purpose, lang));
classification.getContent().add(mdObjectFactory.createPurpose(purposeType));
lom.getClassification().add(classification);
}
return classification;
}
public TechnicalType getTechnical(boolean create) {
LomType lom = getLom(create);
if(lom == null) return null;
TechnicalType technical = lom.getTechnical();
if(technical == null && create) {
technical = mdObjectFactory.createTechnicalType();
lom.setTechnical(technical);
}
return technical;
}
public GeneralType getGeneral(boolean create) {
LomType lom = getLom(create);
if(lom == null) return null;
GeneralType general = lom.getGeneral();
if(general == null && create) {
general = mdObjectFactory.createGeneralType();
lom.setGeneral(general);
}
return general;
}
public EducationalType getEducational(boolean create) {
LomType lom = getLom(create);
if(lom == null) return null;
EducationalType educational = lom.getEducational();
if(educational == null && create) {
educational = mdObjectFactory.createEducationalType();
lom.setEducational(educational);
}
return educational;
}
public void setLifecycleVersion(String version) {
LifecycleType lifecycle = getLifecycle(true);
if(lifecycle != null) {
VersionType type = getFromAny(VersionType.class, lifecycle.getContent());
if(type == null) {
type = mdObjectFactory.createVersionType();
lifecycle.getContent().add(mdObjectFactory.createVersion(type));
}
createOrUpdateFirstLangstring(type.getLangstring(), version, "en");
}
}
public LifecycleType getLifecycle(boolean create) {
LomType lom = getLom(create);
if(lom == null) return null;
LifecycleType lifecycle = lom.getLifecycle();
if(lifecycle == null && create) {
lifecycle = mdObjectFactory.createLifecycleType();
lom.setLifecycle(lifecycle);
}
return lifecycle;
}
public LomType getLom(boolean create) {
LomType lom = getFromAny(LomType.class, getMetadataList());
if(lom == null && create) {
lom = mdObjectFactory.createLomType();
getMetadataList().add(mdObjectFactory.createLom(lom));
}
return lom;
}
/**
* Return the openolat metadata if it exists or, if specified, create
* one and append it to the metadata of the resource.
*
* @param resource The resource with the metadata
* @param create True create the qtiMetadata
* @return
*/
public OpenOLATMetadataType getOpenOLATMetadata(boolean create) {
List<Object> anyMetadataList = getMetadataList();
OpenOLATMetadataType ooMetadata = null;
for(Object anyMetadata:anyMetadataList) {
if(anyMetadata instanceof JAXBElement<?>
&& ((JAXBElement<?>)anyMetadata).getValue() instanceof OpenOLATMetadataType) {
ooMetadata = (OpenOLATMetadataType)((JAXBElement<?>)anyMetadata).getValue();
}
}
if(ooMetadata == null && create) {
ooMetadata = ooObjectFactory.createOpenOLATMetadataType();
getMetadataList().add(ooObjectFactory.createOoMetadata(ooMetadata));
}
return ooMetadata;
}
public void setOpenOLATMetadataQuestionType(String questionType) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setQuestionType(questionType);
}
public void setOpenOLATMetadataMasterIdentifier(String masterIdentifier) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setMasterIdentifier(masterIdentifier);
}
public void setOpenOLATMetadataMasterDifficulty(Double difficulty) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setDifficulty(difficulty);
}
public void setOpenOLATMetadataMasterDiscriminationIndex(Double discriminationIndex) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setDiscriminationIndex(discriminationIndex);
}
public void setOpenOLATMetadataMasterDistractors(Integer distractors) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setDistractors(distractors);
}
public void setOpenOLATMetadataMasterStandardDeviation(Double standardDeviation) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setStandardDeviation(standardDeviation);
}
public void setOpenOLATMetadataUsage(Integer usage) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setUsage(usage);
}
public void setOpenOLATMetadataAssessmentType(String type) {
OpenOLATMetadataType qtiMetadata = getOpenOLATMetadata(true);
qtiMetadata.setAssessmentType(type);
}
/**
* Return the qti metadata if it exists or if specified, create
* one and append it to the metadata of the resource.
*
* @param resource The resource with the metadata
* @param create True create the qtiMetadata
* @return
*/
public QTIMetadataType getQtiMetadata(boolean create) {
List<Object> anyMetadataList = getMetadataList();
QTIMetadataType qtiMetadata = null;
for(Object anyMetadata:anyMetadataList) {
if(anyMetadata instanceof JAXBElement<?>
&& ((JAXBElement<?>)anyMetadata).getValue() instanceof QTIMetadataType) {
qtiMetadata = (QTIMetadataType)((JAXBElement<?>)anyMetadata).getValue();
}
}
if(qtiMetadata == null && create) {
qtiMetadata = qtiObjectFactory.createQTIMetadataType();
getMetadataList().add(qtiObjectFactory.createQtiMetadata(qtiMetadata));
}
return qtiMetadata;
}
public void setQtiMetadataTool(String toolName, String toolVendor, String toolVersion) {
QTIMetadataType qtiMetadata = getQtiMetadata(true);
qtiMetadata.setToolName(toolName);
qtiMetadata.setToolVendor(toolVendor);
qtiMetadata.setToolVersion(toolVersion);
}
public void setQtiMetadata(List<String> interactions) {
QTIMetadataType qtiMetadata = getQtiMetadata(true);
qtiMetadata.getInteractionType().clear();
for(String interaction:interactions) {
qtiMetadata.getInteractionType().add(interaction);
}
}
@SuppressWarnings("unchecked")
private <U> U getFromAny(Class<U> type, List<Object> anyList) {
U object = null;
for(Object any:anyList) {
if(any instanceof JAXBElement<?>
&& ((JAXBElement<?>)any).getValue().getClass().equals(type)) {
object = (U)((JAXBElement<?>)any).getValue();
}
}
return object;
}
private void clearFromAny(String type, List<Object> anyList) {
for(Iterator<Object> anyIterator=anyList.iterator(); anyIterator.hasNext(); ) {
Object any = anyIterator.next();
if(any instanceof JAXBElement<?>
&& ((JAXBElement<?>)any).getName().getLocalPart().equals(type)) {
anyIterator.remove();
}
}
}
private void clearFromAny(Class<?> type, List<Object> anyList) {
for(Iterator<Object> anyIterator=anyList.iterator(); anyIterator.hasNext(); ) {
Object any = anyIterator.next();
if(any instanceof JAXBElement<?>
&& ((JAXBElement<?>)any).getValue().getClass().equals(type)) {
anyIterator.remove();
}
}
}
public List<Object> getMetadataList() {
return metadata == null ? manifestMetadata.getAny() : metadata.getAny();
}
}