tds.itempreview.ConfigBuilder.java Source code

Java tutorial

Introduction

Here is the source code for tds.itempreview.ConfigBuilder.java

Source

/*******************************************************************************
 * 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 tds.itempreview;

import AIR.Common.Helpers.CaseInsensitiveMap;
import AIR.Common.Utilities.Path;
import AIR.Common.Web.Session.Server;
import AIR.Common.collections.IGrouping;
import org.apache.commons.collections.Transformer;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import tds.blackbox.ContentRequestException;
import tds.itemrenderer.ITSDocumentFactory;
import tds.itemrenderer.data.AccLookup;
import tds.itemrenderer.data.IITSDocument;
import tds.itemrenderer.data.ITSTypes.ITSEntityType;
import tds.itemrenderer.data.IrisITSDocument;
import tds.itemrenderer.data.ItsItemIdUtil;

/**
 * @author Shiva BEHERA [sbehera@air.org]
 *
 */
// / <summary>
// / Builds a json config based on file path.
// / </summary>
public class ConfigBuilder {
    private static final Logger _logger = LoggerFactory.getLogger(ConfigBuilder.class);
    private URI _docBaseUri;
    private final String _contentPath;
    private String _filterFormat;
    private String _filterResponseType;
    private Map<String, IrisITSDocument> _documentLookup;
    private Exception _error = null;

    public String getFilterFormat() {
        return _filterFormat;
    }

    public void setFilterFormat(String value) {
        _filterFormat = value;
    }

    public String getFilterResponseType() {
        return _filterResponseType;
    }

    public void setFilterResponseType(String value) {
        _filterResponseType = value;
    }

    public ConfigBuilder(String contentPath) throws URISyntaxException {
        _contentPath = contentPath;
        String basePath = StringUtils.replace(Server.getDocBasePath(), "\\", "/");
        _docBaseUri = new URI("file:///" + StringUtils.replace(basePath, " ", "%20"));
    }

    public Config create() {
        return reloadContent();
    }

    //add the file that was created to the collection
    public Config addFile(String filePath) {
        Collection<IrisITSDocument> itsDocuments = _documentLookup.values();
        Collection<IrisITSDocument> newDocs = this.getITSDocuments(filePath);
        newDocs.addAll(itsDocuments);
        return reloadContent(newDocs);
    }

    //parse the file name in order to remove the correct file
    private String getRemoveKey(String fileName) throws Exception {
        //check if the file is an item or stimulus
        String prefix = "";
        if (fileName.contains("Item")) {
            prefix = "i";
        } else if (fileName.contains("stim")) {
            prefix = "p";
        }

        //parse the file name into parts based on '-'
        String[] parts = fileName.split("-");//todo: add regex
        if (parts.length == 3) {

        } else {
            throw new Exception("invalid key");
        }

        //format and return the file name
        return prefix + "-" + parts[1] + "-" + parts[2];

    }

    //remove a file from the directory by removing it from the collection
    public Config removeFile(String fileName) throws Exception {
        Collection<IrisITSDocument> itsDocuments = _documentLookup.values();
        String key = getRemoveKey(fileName);
        IrisITSDocument documentRemove = _documentLookup.get(key);

        Collection<IrisITSDocument> newDocs = new ArrayList<>();
        newDocs.addAll(itsDocuments);
        newDocs.remove(documentRemove);

        return reloadContent(newDocs);

    }

    private Config reloadContent() {
        Collection<IrisITSDocument> itsDocuments = this.getITSDocuments(this._contentPath);
        return reloadContent(itsDocuments);
    }

    private Config reloadContent(Collection<IrisITSDocument> itsDocuments) {
        try {
            if (itsDocuments != null) {
                itsDocuments = Collections.unmodifiableCollection(itsDocuments);
            }
            List<ITSGroups> itsGroupsList = ItsGroupsList(itsDocuments);
            this._documentLookup = IrisItsDocumentmap(itsDocuments);
            return ReturnValue(itsGroupsList);

        } catch (Exception var8) {
            _logger.error("Error loading IRiS content.", var8);
            this._error = var8;
            throw var8;
        }
    }

    private Config ReturnValue(List<ITSGroups> itsGroupsList) {
        return this.buildConfigPages(itsGroupsList);

    }

    private List<ITSGroups> ItsGroupsList(Collection<IrisITSDocument> itsDocuments) {
        if (itsDocuments != null) {
            itsDocuments = Collections.unmodifiableCollection(itsDocuments);
        }
        Collection<IGrouping<String, IrisITSDocument>> groupDocumentsByFolders = this
                .groupDocumentsByParentFolder(itsDocuments);
        List<ITSGroups> itsGroupsList = new ArrayList();
        Iterator i$ = groupDocumentsByFolders.iterator();

        while (i$.hasNext()) {
            IGrouping<String, IrisITSDocument> groupedDocuments = (IGrouping) i$.next();
            ITSGroups itsGroups = this.createITSGroups(groupedDocuments);
            itsGroupsList.add(itsGroups);
        }

        return itsGroupsList;
    }

    private Map<String, IrisITSDocument> IrisItsDocumentmap(Collection<IrisITSDocument> itsDocuments) {
        if (itsDocuments != null) {
            itsDocuments = Collections.unmodifiableCollection(itsDocuments);
        }

        Map<String, IrisITSDocument> documentsMap = new CaseInsensitiveMap();
        Iterator i$ = itsDocuments.iterator();

        while (i$.hasNext()) {
            IrisITSDocument itsDocument = (IrisITSDocument) i$.next();
            documentsMap.put(ItsItemIdUtil.getItsDocumentId(itsDocument), itsDocument);
        }

        return Collections.unmodifiableMap(documentsMap);
    }

    public IrisITSDocument getDocumentRepresentation(String id) throws ContentRequestException {
        if (_error != null) {
            throw new ContentRequestException("Content not loaded properly.", _error);
        }
        if (_documentLookup.containsKey(id)) {
            return _documentLookup.get(id);
        }
        throw new ContentRequestException(String.format("No content found by id %s", id));
    }

    public IITSDocument getRenderableDocument(String id) throws ContentRequestException {
        IrisITSDocument documentRepresentation = getDocumentRepresentation(id);
        // In the below code there is no way to set accommodations.
        // We need to provide a way as this is common code also used by ItemPreview.
        return correctBaseUri(ITSDocumentFactory.load(documentRepresentation.getRealPath(), "ENU", true));
    }

    public IITSDocument getRenderableDocument(String id, AccLookup accLookup) throws ContentRequestException {
        IrisITSDocument documentRepresentation = getDocumentRepresentation(id);
        return correctBaseUri(ITSDocumentFactory.load(documentRepresentation.getRealPath(), accLookup, true));
    }

    // / <summary>
    // / Takes an array of xml files and parses into passage/item documents.
    // / </summary>
    private Collection<IrisITSDocument> getITSDocuments(final String contentPath) {
        // get all xml files in the content path
        final Collection<File> xmlFiles = Path.getFilesMatchingExtensions(contentPath, new String[] { "xml" });

        Collection<IrisITSDocument> returnList = new ArrayList<>();

        for (File file : xmlFiles) {
            final String xmlFile = file.getAbsolutePath();
            try {
                final IITSDocument itsDocument = correctBaseUri(
                        ITSDocumentFactory.loadUri2(xmlFile, AccLookup.getNone(), false));
                IrisITSDocument irisDocument = new IrisITSDocument(itsDocument, xmlFile);
                returnList.add(irisDocument);
            } catch (Exception exp) {
                _logger.error("Exception while adding itsdocument to collection.", exp);
            }
        }
        return returnList;
    }

    private Collection<IGrouping<String, IrisITSDocument>> groupDocumentsByParentFolder(
            Collection<IrisITSDocument> itsDocuments) {
        Transformer groupTransformer = new Transformer() {

            @Override
            public Object transform(Object itsDocument) {
                return ((IITSDocument) itsDocument).getFolderName();
            }
        };

        List<IGrouping<String, IrisITSDocument>> returnList = IGrouping
                .<String, IrisITSDocument>createGroups(itsDocuments, groupTransformer);

        Collections.sort(returnList, new Comparator<IGrouping<String, IrisITSDocument>>() {
            @Override
            public int compare(IGrouping<String, IrisITSDocument> o1, IGrouping<String, IrisITSDocument> o2) {
                return o1.getKey().compareTo(o2.getKey());
            }
        });

        return returnList;
    }

    private ITSGroups createITSGroups(Collection<IrisITSDocument> itsDocuments) {
        boolean ignorePassages = ItemPreviewSettings.getIgnorePassages().getValue();

        List<IrisITSDocument> itsPassages = new ArrayList<IrisITSDocument>();
        List<IrisITSDocument> itsItems = new ArrayList<IrisITSDocument>();

        // split up passages and items
        for (IrisITSDocument itsDocument : itsDocuments) {
            if (itsDocument.getType() == ITSEntityType.Passage) {
                if (ignorePassages)
                    itsPassages.add(itsDocument);
            } else if (itsDocument.getType() == ITSEntityType.Item) {
                itsItems.add(itsDocument);
            }
        }

        Map<String, ITSGroup> groupLookup = new HashMap<String, ITSGroup>();

        // create groups out of the passages
        for (IITSDocument itsPassage : itsPassages) {
            String groupID = itsPassage.getGroupID();
            if (groupLookup.containsKey(groupID))
                continue;

            ITSGroup itsGroup = new ITSGroup(groupID);
            itsGroup.setPassage(itsPassage);
            groupLookup.put(groupID, itsGroup);
        }

        for (IITSDocument item : itsItems) {
            String itemGroupID = item.getGroupID();

            // check if passage
            if (ignorePassages && item.getStimulusKey() > 0) {
                // use item id instead of group
                itemGroupID = item.getID();
            }

            ITSGroup group = null;
            if (groupLookup.containsKey(itemGroupID))
                group = groupLookup.get(itemGroupID);

            if (group == null) {
                group = new ITSGroup(itemGroupID);
                groupLookup.put(itemGroupID, group);
            }

            if (group.getItems() == null)
                group.setItems(new ArrayList<IITSDocument>());
            group.getItems().add(item);
        }

        ITSGroups itsGroups = new ITSGroups();
        for (ITSGroup itsGroup : groupLookup.values()) {
            // if there is a filter ignore empty groups
            if (getFilterFormat() != null || getFilterResponseType() != null) {
                if (itsGroup.getItems() == null || itsGroup.getItems().size() == 0)
                    continue;
            }
            itsGroups.add(itsGroup);
        }
        return itsGroups;
    }

    private Config buildConfigPages(Collection<ITSGroups> itsGroupsList) {
        boolean ignorePassages = ItemPreviewSettings.getIgnorePassages().getValue();
        String passageLayout = ItemPreviewSettings.getPassageLayout().getValue();
        boolean passageReplace = ignorePassages
                && !(StringUtils.isEmpty(passageLayout) || StringUtils.isWhitespace(passageLayout));

        Config config = new Config();
        config.setSections(new ArrayList<Section>());
        config.setPages(new ArrayList<Page>());

        for (ITSGroups itsGroups : itsGroupsList) {
            ITSGroup firstGroup = itsGroups == null || itsGroups.size() == 0 ? null : itsGroups.get(0);
            if (firstGroup == null)
                continue;

            String sectionLbl = firstGroup.getGroupingText();
            String sectionID = StringUtils.replace(sectionLbl, " ", "");

            // create section
            Section configSection = new Section();
            configSection.setId(sectionID);
            configSection.setLabel(sectionLbl);
            config.getSections().add(configSection);

            // create pages
            for (ITSGroup itsGroup : itsGroups) {
                Page configPage = new Page();
                // configPage.ID = itsGroup.GroupID;
                configPage.setLabel(itsGroup.getLabel());
                configPage.setSectionId(configSection.getId());

                // create passage
                if (itsGroup.getPassage() != null) {
                    Content configPassage = new Content();
                    setDocumentInfo(configPassage, itsGroup.getPassage());
                    configPage.setPassage(configPassage);
                }

                // create items
                if (itsGroup.getItems() != null && itsGroup.getItems().size() > 0) {
                    configPage.setItems(new ArrayList<Item>());

                    for (IITSDocument itsItem : itsGroup.getItems()) {
                        Item configItem = new Item();
                        setDocumentInfo(configItem, itsItem);
                        configPage.getItems().add(configItem);

                        // check if replace passage layout
                        if (passageReplace && itsGroup.getItems().size() == 1 && itsItem.getStimulusKey() > 0) {
                            configPage.setLayoutName(passageLayout);
                        }
                    }

                }

                config.getPages().add(configPage);
            }
        }

        return config;
    }

    // / <summary>
    // / Add ITS document info to the config content object.
    // / </summary>
    private void setDocumentInfo(Content configContent, IITSDocument itsDocument) {
        configContent.setFile(itsDocument.getBaseUri());

        if (configContent instanceof Item) {
            Item configItem = (Item) configContent;
            configItem.setBankKey(itsDocument.getBankKey());
            configItem.setItemKey(itsDocument.getItemKey());
        }
    }

    // Shiva: hack! the problem is ITSDocumentFactory.loadUri2 internally calls
    // getUriOriginalString() and that is definitely buggy. Talk to John about
    // that.
    // it drops the protocol. So what we will do is if the uri parameter starts
    // with the uri for current doc base then we will convert into a relative
    // path.
    private IITSDocument correctBaseUri(IITSDocument itsDocument) {
        String itsDocumentBaseUri = itsDocument.getBaseUri();
        int indexOf = itsDocumentBaseUri.indexOf(_docBaseUri.getRawPath());
        if (indexOf == 0) {
            itsDocumentBaseUri = itsDocumentBaseUri.substring(_docBaseUri.getRawPath().length());
            if (itsDocumentBaseUri.startsWith("/"))
                itsDocument.setBaseUri("~" + itsDocumentBaseUri);
            else
                itsDocument.setBaseUri("~/" + itsDocumentBaseUri);
        }
        return itsDocument;
    }
}