Java tutorial
/******************************************************************************* * Educational Online Test Delivery System * Copyright (c) 2014 American Institutes for Research * * Distributed under the AIR Open Source License, Version 1.0 * See accompanying file AIR-License-1_0.txt or at * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf ******************************************************************************/ package org.opentestsystem.authoring.testitembank.service.impl; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.json.JSONException; import org.json.JSONObject; import org.json.XML; import org.opentestsystem.authoring.testitembank.apipzip.domain.ApipItemMetadata; import org.opentestsystem.authoring.testitembank.apipzip.domain.ApipManifest; import org.opentestsystem.authoring.testitembank.apipzip.domain.ApipManifestDependency; import org.opentestsystem.authoring.testitembank.apipzip.domain.ApipManifestResource; import org.opentestsystem.authoring.testitembank.apipzip.domain.ZipMetadata; import org.opentestsystem.authoring.testitembank.apipzip.domain.ZipSmarterAppItemMetadata; import org.opentestsystem.authoring.testitembank.domain.Item; import org.opentestsystem.authoring.testitembank.exception.TestItemBankException; import org.opentestsystem.authoring.testitembank.service.ZipXMLService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; public class ZipXMLServiceImpl implements ZipXMLService { private static final Logger LOGGER = LoggerFactory.getLogger(ZipXMLServiceImpl.class); private static final String SMARTER_APP_METADATA_KEY = "smarterAppMetadata"; private static final String METADATA_KEY = "metadata"; private static final String LANGUAGE_KEY = "Language"; private static final int PRETTY_PRINT_INDENT_FACTOR = 4; private static JAXBContext jaxbContext; private static final String SMARTER_ENGLISH_LANG = "eng"; private static final String SMARTER_SPANISH_LANG = "spa"; private static final String ITEM_ENGLISH_LANG = "ENU"; private static final String ITEM_SPANISH_LANG = "ESN"; private static final String ITEM_ENGLISH_BRAILLE_LANG = "ENU-Braille"; private static final String NOT_BRAILLABLE_TYPE = "Not Braillable"; private static ObjectMapper STATIC_JSON_MAPPER = new ObjectMapper(); static { try { jaxbContext = JAXBContext.newInstance( new Class[] { ApipManifest.class, ApipManifestResource.class, ApipManifestDependency.class }); } catch (final JAXBException e) { throw new TestItemBankException("invalid.jaxb.context", e); } STATIC_JSON_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); STATIC_JSON_MAPPER.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); } private static class APIP_RESOURCE_IDENTIFIER_FILTER implements Predicate<ApipManifestResource> { private final String targetIdentifier; private APIP_RESOURCE_IDENTIFIER_FILTER(final String targetIdentifier) { this.targetIdentifier = targetIdentifier; } public static APIP_RESOURCE_IDENTIFIER_FILTER getInstance(final String targetIdentifier) { return new APIP_RESOURCE_IDENTIFIER_FILTER(targetIdentifier); } @Override public boolean apply(final ApipManifestResource apipManifestResource) { return this.targetIdentifier.equals(apipManifestResource.getIdentifier()); } }; @Override public void writeToManifestToOutputStream(final ApipManifest manifest, final OutputStream outputStream) throws JAXBException { final Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.marshal(manifest, outputStream); } @Override public Item buildItem(final ApipManifestResource resource, final ApipItemMetadata apipMetadata, final String gridfsId, final String tenantId, final String itemBank) { Map<String, Object> itemMetadata; if (apipMetadata == null) { itemMetadata = new HashMap<String, Object>(); } else { itemMetadata = Maps.newHashMap(apipMetadata.getMetadata()); } Item item = new Item(); try { item.setIdentifier(resource.getIdentifier()); item.setOriginalZipGridId(gridfsId); if (apipMetadata != null) { ZipMetadata zipMetadataFile = STATIC_JSON_MAPPER.readValue(apipMetadata.getMetadataJson(), ZipMetadata.class); ZipSmarterAppItemMetadata smarterAppMetadata = zipMetadataFile.getMetadata() .getSmarterAppMetadata(); item.setTenantId(tenantId); item.setItemBank(itemBank); item.setInteractionType(smarterAppMetadata.getInteractionType()); item.setVersion(smarterAppMetadata.getVersion()); item.setIntendedGrade(smarterAppMetadata.getIntendedGrade()); item.setSubject(smarterAppMetadata.getSubject()); item.setStatus(smarterAppMetadata.getStatus()); item.setStimulusName(smarterAppMetadata.getStimulusName()); item.setAssociatedStimulus(smarterAppMetadata.getAssociatedStimulus()); item.setAssociatedTutorial(smarterAppMetadata.getAssociatedTutorial()); item.setAssociatedWordlist(smarterAppMetadata.getAssociatedWordlist()); //item.setLanguages(smarterAppMetadata.getLanguages()); String brailleType = smarterAppMetadata.getBrailleType(); // Convert languages into format TDS expects; add Braille, if needed List<String> itemLanguages = null; List<String> smarterLanguages = smarterAppMetadata.getLanguages(); if (smarterLanguages != null) { itemLanguages = new ArrayList<String>(); for (String lang : smarterLanguages) { if (SMARTER_ENGLISH_LANG.equalsIgnoreCase(lang)) { itemLanguages.add(ITEM_ENGLISH_LANG); if (!StringUtils.isEmpty(brailleType) && !NOT_BRAILLABLE_TYPE.equalsIgnoreCase(brailleType)) itemLanguages.add(ITEM_ENGLISH_BRAILLE_LANG); } else if (SMARTER_SPANISH_LANG.equalsIgnoreCase(lang)) { itemLanguages.add(ITEM_SPANISH_LANG); } else { itemLanguages.add(lang); } } } item.setLanguages(itemLanguages); item.setItemEnemies(smarterAppMetadata.getEnemyItems()); item.setItemScoreDimensionList(smarterAppMetadata.getItemScoreDimensionList()); item.setItemStandardPublicationList(smarterAppMetadata.getItemStandardPublicationList()); // Convert itemMetadata languages into format TDS expects if (itemMetadata.containsKey(LANGUAGE_KEY)) { itemMetadata.put(LANGUAGE_KEY, itemLanguages); } item.setAllIncludedMetatdata(itemMetadata); } } catch (IOException e) { LOGGER.error("unable to parse metdata into item format for key fields", e); } catch (Exception ee) { LOGGER.error("error rebuilding item metadata ", ee); } return item; } @Override @SuppressWarnings("unchecked") public ApipItemMetadata extractMetadataFromXML(final InputStream inputstream) { final ApipItemMetadata apipMetadata = new ApipItemMetadata(); Map<String, Object> metadata = new HashMap<String, Object>(); String jsonPrettyPrintString = ""; try { // List<String> lines = Files.readAllLines(metadataFile.toPath(), StandardCharsets.UTF_8); StringWriter writer = new StringWriter(); IOUtils.copy(inputstream, writer, StandardCharsets.UTF_8); String xml = writer.toString(); JSONObject xmlJSONObj = XML.toJSONObject(xml); jsonPrettyPrintString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR); HashMap<String, Object> mapFromJson = STATIC_JSON_MAPPER.readValue(jsonPrettyPrintString, new TypeReference<HashMap<String, Object>>() { }); HashMap<String, Object> mp = convertValueToString(mapFromJson); HashMap<String, Object> metadataTags = (HashMap<String, Object>) mp.get(METADATA_KEY); HashMap<String, Object> smarterAppMetadataTags = (HashMap<String, Object>) metadataTags .get(SMARTER_APP_METADATA_KEY); populateMap(metadata, smarterAppMetadataTags, Arrays.asList(new String[] {})); populateMap(metadata, metadataTags, Arrays.asList(new String[] { SMARTER_APP_METADATA_KEY })); } catch (JSONException | IOException je) { System.out.println(je.toString()); } apipMetadata.setMetadata(metadata); apipMetadata.setMetadataJson(jsonPrettyPrintString); return apipMetadata; } private HashMap<String, Object> convertValueToString(HashMap<String, Object> objMap) { HashMap<String, Object> newMap = new HashMap<String, Object>(); for (Entry<String, Object> mapEntry : objMap.entrySet()) { newMap.put(mapEntry.getKey(), convertToString(mapEntry.getValue())); } return newMap; } @SuppressWarnings("unchecked") private Object convertToString(Object objectToConvert) { Object newVal = null; if (objectToConvert instanceof List) { List<Object> newList = new ArrayList<Object>(); List<Object> origList = (List<Object>) objectToConvert; for (Object listObj : origList) { newList.add(convertToString(listObj)); } newVal = newList; } else if (objectToConvert instanceof Map) { Map<String, Object> origMap = (Map<String, Object>) objectToConvert; HashMap<String, Object> newMap = new HashMap<String, Object>(); for (Entry<String, Object> mapEntry : origMap.entrySet()) { newMap.put(mapEntry.getKey(), convertToString(mapEntry.getValue())); } newVal = newMap; } else { newVal = objectToConvert.toString(); } return newVal; } @SuppressWarnings("unchecked") private void populateMap(Map<String, Object> searchableMetadata, HashMap<String, Object> importedMetadata, List<String> excludedTags) { for (Entry<String, Object> entries : importedMetadata.entrySet()) { if (!excludedTags.contains(entries.getKey())) { Object currentObjects = searchableMetadata.get(entries.getKey()); if (currentObjects == null) { searchableMetadata.put(entries.getKey(), entries.getValue()); } else { List<Object> objectList; if (currentObjects instanceof List) { objectList = (List<Object>) currentObjects; } else { objectList = new ArrayList<Object>(); objectList.add(currentObjects); } if (entries.getValue() instanceof List) { objectList.addAll((List<Object>) entries.getValue()); } else { objectList.add(entries.getValue()); } } } } } @Override public ApipManifest extractManifestFromXML(final InputStream inputstream) { ApipManifest manifest = null; try (InputStream input = inputstream) { final Unmarshaller um = jaxbContext.createUnmarshaller(); final JAXBElement<ApipManifest> myJAXBObject = um.unmarshal(getDocument(input), ApipManifest.class); manifest = myJAXBObject.getValue(); } catch (final Exception e) { throw new TestItemBankException("apip.zip.extractor.failure.mainfest", e); } return manifest; } private Document getDocument(final InputStream input) throws Exception { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(input); } @Override public ApipManifest consolidateManifests(final String targetIdentifier, final List<ApipManifest> manifests) { final ApipManifest consolidatedManifest = new ApipManifest(); consolidatedManifest.setIdentifier(targetIdentifier); consolidatedManifest.setResources(new ArrayList<ApipManifestResource>()); for (final ApipManifest manifest : manifests) { for (final ApipManifestResource resource : manifest.getResources()) { final boolean containsIdentifier = Iterables.tryFind(consolidatedManifest.getResources(), APIP_RESOURCE_IDENTIFIER_FILTER.getInstance(resource.getIdentifier())).isPresent(); if (!containsIdentifier) { consolidatedManifest.getResources().add(resource); } } } Collections.sort(consolidatedManifest.getResources(), ApipManifestResource.BY_IDENTIFIER_ORDERING); return consolidatedManifest; } }