Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import dev.jcputney.elearning.parser.input.PackageManifest;
import dev.jcputney.elearning.parser.input.lom.LOM;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.ADLObjective;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.MapInfo;
import dev.jcputney.elearning.parser.input.scorm2004.adl.types.ScormType;
import dev.jcputney.elearning.parser.input.scorm2004.ims.cp.Scorm2004CourseMetadata;
import dev.jcputney.elearning.parser.input.scorm2004.ims.cp.Scorm2004Item;
Expand Down Expand Up @@ -517,9 +519,9 @@ public Set<String> getGlobalObjectiveIds() {
.getOrganizationList()
.stream()
.flatMap(org -> safeStream(org.getItems())) // Null-safe stream for items
.flatMap(item -> safeStream(getObjectives(item))) // Null-safe stream for objectives
.flatMap(obj -> safeStream(obj.getMapInfo())) // Null-safe stream for mapInfo
.map(Scorm2004ObjectiveMapping::getTargetObjectiveID)
.flatMap(item -> Stream.concat(
getObjectiveMappings(item).map(Scorm2004ObjectiveMapping::getTargetObjectiveID),
getAdlObjectiveMappings(item).map(MapInfo::getTargetObjectiveID)))
.filter(id -> id != null && !id.isEmpty()) // Filter non-null and non-empty IDs
.collect(Collectors.toSet());
}
Expand Down Expand Up @@ -866,16 +868,38 @@ public int hashCode() {
* @param item The SCORM item to retrieve objectives from.
* @return A list of objectives, or an empty list if null.
*/
private List<Scorm2004Objective> getObjectives(Scorm2004Item item) {
private Stream<Scorm2004ObjectiveMapping> getObjectiveMappings(Scorm2004Item item) {
if (item.getSequencing() != null && item
.getSequencing()
.getObjectives() != null) {
return item
var objectives = item
.getSequencing()
.getObjectives()
.getObjectiveList();
.getObjectives();
return Stream
.concat(Stream.ofNullable(objectives.getPrimaryObjective()),
safeStream(objectives.getObjectiveList()))
.flatMap(objective -> safeStream(objective.getMapInfo()));
}
return List.of(); // Return an empty list if objectives are null
return Stream.empty();
}

/**
* Retrieves ADL mapInfo entries from a given item in a null-safe manner.
*
* @param item The SCORM item to retrieve ADL objective mappings from.
* @return A stream of ADL mapInfo entries, or an empty stream if none exist.
*/
private Stream<MapInfo> getAdlObjectiveMappings(Scorm2004Item item) {
if (item.getSequencing() != null && item
.getSequencing()
.getAdlObjectives() != null) {
return safeStream(item
.getSequencing()
.getAdlObjectives()
.getObjectiveList())
.flatMap((ADLObjective objective) -> safeStream(objective.getMapInfoList()));
}
return Stream.empty();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import dev.jcputney.elearning.parser.input.scorm2004.adl.cp.CompletionThreshold;
import dev.jcputney.elearning.parser.input.scorm2004.adl.navigation.NavigationInterface;
import dev.jcputney.elearning.parser.input.scorm2004.adl.navigation.Presentation;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.ADLObjectives;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.ConstrainChoiceConsiderations;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.RollupConsiderations;
import dev.jcputney.elearning.parser.input.scorm2004.adl.types.ScormType;
Expand Down Expand Up @@ -567,6 +568,16 @@ private static boolean hasObjectives(Scorm2004Objectives objectives) {
|| isNotEmpty(objectives.getObjectiveList());
}

/**
* Determines if the provided ADL objectives object has objectives defined.
*
* @param objectives the ADL objectives object to inspect; may be null
* @return true if the ADL objectives object contains at least one objective
*/
private static boolean hasObjectives(ADLObjectives objectives) {
return objectives != null && isNotEmpty(objectives.getObjectiveList());
}

/**
* Determines if the provided RollupRules object has at least one significant rule or condition
* defined. This method evaluates the list of rollup rules and other attributes within the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2024-2026 Jonathan Putney
*
* Licensed 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 the project root LICENSE file
* or at http://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*/
package dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import dev.jcputney.elearning.parser.input.scorm2004.ADLSeq;
import java.io.Serializable;
import java.util.List;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

/**
* Represents the ADL sequencing objectives container.
*
* <p>SCORM 2004 defines {@code adlseq:objectives} separately from IMS Simple Sequencing
* {@code imsss:objectives}. The ADL container contains one or more {@code adlseq:objective}
* elements whose {@code adlseq:mapInfo} children expose additional score, completion, and progress
* mapping flags.</p>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public final class ADLObjectives implements Serializable {

/**
* ADL objectives in document order.
*/
@JacksonXmlElementWrapper(localName = "objective", useWrapping = false)
@JacksonXmlProperty(localName = "objective", namespace = ADLSeq.NAMESPACE_URI)
private List<ADLObjective> objectiveList;

/**
* Default constructor for Jackson and callers that populate the container manually.
*/
public ADLObjectives() {
// no-op
}

/**
* Constructs an ADL objectives container with the supplied objective list.
*
* @param objectiveList ADL objectives in document order
*/
public ADLObjectives(List<ADLObjective> objectiveList) {
this.objectiveList = objectiveList;
}

/**
* Returns the ADL objectives in document order.
*
* @return ADL objectives, or null if none were parsed
*/
public List<ADLObjective> getObjectiveList() {
return this.objectiveList;
}

/**
* Sets the ADL objectives in document order.
*
* @param objectiveList ADL objectives to assign
*/
public void setObjectiveList(List<ADLObjective> objectiveList) {
this.objectiveList = objectiveList;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}

if (!(o instanceof ADLObjectives that)) {
return false;
}

return new EqualsBuilder()
.append(getObjectiveList(), that.getObjectiveList())
.isEquals();
}

@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(getObjectiveList())
.toHashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import dev.jcputney.elearning.parser.input.scorm2004.ADLSeq;
import dev.jcputney.elearning.parser.input.scorm2004.IMSSS;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.ADLObjectives;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.ConstrainChoiceConsiderations;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.RollupConsiderations;
import dev.jcputney.elearning.parser.input.scorm2004.ims.ss.objective.Scorm2004Objectives;
Expand Down Expand Up @@ -87,8 +88,7 @@ public final class Sequencing implements Serializable {
* The ADL objectives for this sequencing element.
*/
@JacksonXmlProperty(localName = "objectives", namespace = ADLSeq.NAMESPACE_URI)
@JsonProperty("adlObjectives")
private Scorm2004Objectives adlObjectives;
private ADLObjectives adlObjectives;

/**
* Controls the randomization of child activities within a sequence.
Expand Down Expand Up @@ -282,22 +282,21 @@ public void setObjectives(Scorm2004Objectives objectives) {
/**
* Retrieves the ADL-specific objectives associated with this sequencing object.
*
* @return the ADL objectives as a {@code Scorm2004Objectives} object
* @return the ADL objectives as an {@code ADLObjectives} object
*/
@JsonProperty("adlObjectives")
public Scorm2004Objectives getAdlObjectives() {
public ADLObjectives getAdlObjectives() {
return this.adlObjectives;
}

/**
* Sets the ADL-specific objectives for the sequencing object.
*
* @param adlObjectives the {@code Scorm2004Objectives} object representing the set of ADL
* objectives used to assess and track progress and performance within the SCORM 2004 sequencing
* model.
* @param adlObjectives the {@code ADLObjectives} object representing the set of ADL objectives
* used to assess and track progress and performance within the SCORM 2004 sequencing model.
*/
@JsonProperty("adlObjectives")
public void setAdlObjectives(Scorm2004Objectives adlObjectives) {
public void setAdlObjectives(ADLObjectives adlObjectives) {
this.adlObjectives = adlObjectives;
Comment thread
jcputney marked this conversation as resolved.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import dev.jcputney.elearning.parser.input.scorm2004.Scorm2004Manifest;
import dev.jcputney.elearning.parser.input.scorm2004.SequencingUsageDetector;
import dev.jcputney.elearning.parser.input.scorm2004.SequencingUsageDetector.SequencingLevel;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.ADLObjective;
import dev.jcputney.elearning.parser.input.scorm2004.adl.sequencing.MapInfo;
import dev.jcputney.elearning.parser.input.scorm2004.adl.types.ScormType;
import dev.jcputney.elearning.parser.input.scorm2004.ims.cp.Scorm2004Item;
import dev.jcputney.elearning.parser.input.scorm2004.ims.cp.Scorm2004Resource;
Expand Down Expand Up @@ -223,7 +225,7 @@ public static Scorm2004Metadata create(Scorm2004Manifest manifest, boolean xapiE
}

/**
* Retrieves the list of objectives from a given item in a null-safe manner.
* Retrieves the list of IMS objectives from a given item in a null-safe manner.
*
* @param item The SCORM item to retrieve objectives from.
* @return A list of objectives, or an empty list if null.
Expand All @@ -232,14 +234,36 @@ private static List<Scorm2004Objective> getObjectives(Scorm2004Item item) {
if (item.getSequencing() != null && item
.getSequencing()
.getObjectives() != null) {
return item
var objectives = item
.getSequencing()
.getObjectives()
.getObjectiveList();
.getObjectives();
return Stream
.concat(Stream.ofNullable(objectives.getPrimaryObjective()),
safeStream(objectives.getObjectiveList()))
.toList();
}
return List.of(); // Return an empty list if objectives are null
}

/**
* Retrieves the list of ADL objectives from a given item in a null-safe manner.
*
* @param item The SCORM item to retrieve ADL objectives from.
* @return A list of ADL objectives, or an empty list if null.
*/
private static List<ADLObjective> getAdlObjectives(Scorm2004Item item) {
if (item.getSequencing() != null && item
.getSequencing()
.getAdlObjectives() != null) {
List<ADLObjective> objectives = item
.getSequencing()
.getAdlObjectives()
.getObjectiveList();
return objectives != null ? objectives : List.of();
}
return List.of();
Comment thread
jcputney marked this conversation as resolved.
}

/**
* Wraps a potentially null collection in a stream.
*
Expand Down Expand Up @@ -624,9 +648,13 @@ private Set<String> collectGlobalObjectiveIds() {
.getOrganizationList()
.stream()
.flatMap(org -> safeStream(org.getItems()))
.flatMap(item -> safeStream(getObjectives(item)))
.flatMap(obj -> safeStream(obj.getMapInfo()))
.map(Scorm2004ObjectiveMapping::getTargetObjectiveID)
.flatMap(item -> Stream.concat(
safeStream(getObjectives(item))
.flatMap(obj -> safeStream(obj.getMapInfo()))
.map(Scorm2004ObjectiveMapping::getTargetObjectiveID),
safeStream(getAdlObjectives(item))
.flatMap(obj -> safeStream(obj.getMapInfoList()))
.map(MapInfo::getTargetObjectiveID)))
.filter(id -> id != null && !id.isEmpty())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
Expand Down
Loading