package fi.utu.ville.exercises.stub; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; import com.vaadin.ui.Alignment; import com.vaadin.ui.Component; import com.vaadin.ui.VerticalLayout; import fi.utu.ville.exercises.helpers.StandardSubmissionType; import fi.utu.ville.exercises.model.Editor; import fi.utu.ville.exercises.model.ExecutionSettings; import fi.utu.ville.exercises.model.Executor; import fi.utu.ville.exercises.model.ExerciseException; import fi.utu.ville.exercises.model.ExerciseTypeDescriptor; import fi.utu.ville.exercises.model.GeneralExerciseInfo; import fi.utu.ville.exercises.model.StatisticalSubmissionInfo; import fi.utu.ville.exercises.model.SubmissionInfo; import fi.utu.ville.standardutils.Localizer; import fi.utu.ville.standardutils.StandardUIFactory; import fi.utu.ville.standardutils.TempFilesManager; /** * A quick-and-dirty class for loading {@link Executor} -implementor for testing and storing {@link SubmissionInfo}-objects from submissions made using it. * * @author Riku Haavisto * * @param <S> * tested {@link SubmissionInfo}-implementor */ class TestingExerciseView<S extends SubmissionInfo> extends VerticalLayout { private static final Logger logger = Logger .getLogger(TestingExerciseView.class.getName()); private static final String testingExerViewId = "testingexerview"; private static final long serialVersionUID = 6423843365009117711L; /** * Loads and returns a new {@link TestingExerciseView} suitable for testing exercises in student-mode. * * @param toLoad * {@link ExerciseTypeDescriptor} for the exercise-type for which to load an {@link Executor} * @param localizer * {@link Localizer} for localizing the UI * @param exerInfo * {@link GeneralExerciseInfo} storing general info on the exercise-instance * @param execSettings * {@link ExecutionSettings} to use * @param tempMan * {@link TempFilesManager} for managing temporary files * @return the loaded {@link TestingExerciseView} */ public static <S extends SubmissionInfo> TestingExerciseView<S> getViewForStudentTesting( ExerciseTypeDescriptor<?, S> toLoad, Localizer localizer, GeneralExerciseInfo exerInfo, ExecutionSettings execSettings, TempFilesManager tempMan) { Executor<?, S> execToUse = null; String exerName = exerInfo.getName(); try { execToUse = StubExertypeClassLoader.loadExecutor(toLoad, exerName, localizer, execSettings, tempMan); } catch (ExerciseException e) { // informing the user is handled by detecting the possible null // executor logger.log(Level.WARNING, "", e); } return getViewFor(execToUse, exerInfo, false, localizer, toLoad, tempMan); } /** * Loads and returns a {@link TestingExerciseView} suitable for testing exercise-instances directly from {@link Editor} while still under editing. * * @param execToUse * pre-loaded {@link Executor} to use * @param exerInfo * {@link GeneralExerciseInfo} with general info on exercise * @param localizer * {@link Localizer} for localizing the UI * @param tempMan * {@link TempFilesManager} for managing temporary files * @return newly constructed {@link TestingExerciseView} */ public static TestingExerciseView<?> getViewForTestingInEditor( Executor<?, ? extends SubmissionInfo> execToUse, GeneralExerciseInfo exerInfo, Localizer localizer, TempFilesManager tempMan) { // descriptor is not needed here as it is only used to get correct // path for saving submission-infos return getViewFor(execToUse, exerInfo, true, localizer, null, tempMan); } /** * Constructs and returns a new {@link TestingExerciseView}. * * @param execToUse * pre-loaded {@link Executor} * @param exerInfo * general info on exercise * @param editorTest * whether the view is for testing exercise in editor, or for 'real' student-side testing (ie. whether to save submissions) * @param localizer * {@link Localizer} for localizing the UI * @param toLoad * {@link ExerciseTypeDescriptor} of the exercise-type used * @param tempMan * {@link TempFilesManager} for managing temporary files * @return newly constructed {@link TestingExerciseView} */ private static <S extends SubmissionInfo> TestingExerciseView<S> getViewFor( Executor<?, S> execToUse, GeneralExerciseInfo exerInfo, boolean editorTest, Localizer localizer, ExerciseTypeDescriptor<?, S> toLoad, TempFilesManager tempMan) { return new TestingExerciseView<>(execToUse, exerInfo, editorTest, localizer, toLoad, tempMan); } private final Executor<?, S> currentExecutor; private final GeneralExerciseInfo exerInfo; private final boolean editorTest; private final Localizer localizer; private final ExerciseTypeDescriptor<?, S> stubUsed; private final TempFilesManager tempMan; /** * Constructs a new {@link TestingExerciseView}. * * @param execToUse * pre-loaded {@link Executor} * @param exerInfo * general info on exercise * @param editorTest * whether the view is for testing exercise in editor, or for 'real' student-side testing (ie. whether to save submissions) * @param localizer * {@link Localizer} for localizing the UI * @param desc * {@link ExerciseTypeDescriptor} of the exercise-type used * @param tempMan * {@link TempFilesManager} for managing temporary files */ private TestingExerciseView(Executor<?, S> execToUse, GeneralExerciseInfo exerInfo, boolean editorTest, Localizer localizer, ExerciseTypeDescriptor<?, S> desc, TempFilesManager tempMan) { this.tempMan = tempMan; this.localizer = localizer; currentExecutor = execToUse; this.exerInfo = exerInfo; this.editorTest = editorTest; this.stubUsed = desc; setId(testingExerViewId); doLayout(); } /** * Draws the UI and attaches needed listeners to the {@link Executor} */ private void doLayout() { removeAllComponents(); setMargin(true); setSpacing(true); setWidth("100%"); if (!editorTest) { this.addComponent(new StubViewHeaderBar(localizer, localizer .getUIText(StubUiConstants.EXECUTOR_TEST_INFO))); } if (currentExecutor == null) { this.addComponent(StandardUIFactory .getInformationPanel(StubUiConstants.EXECUTOR_LOAD_ERROR)); } else { addComponent(new TestingExerciseInfoView(localizer, exerInfo, stubUsed)); addComponent(new ResetSubmitControlView(localizer, currentExecutor)); Component exerLayout = currentExecutor.getView(); addComponent(exerLayout); setComponentAlignment(exerLayout, Alignment.TOP_CENTER); setExpandRatio(exerLayout, 1.0f); currentExecutor.registerSubmitListener(submission -> { if (!Arrays.asList(StandardSubmissionType.values()) .contains(submission.getSubmissionType())) { throw new IllegalArgumentException( "For correct behavior the SubmissionType from " + "askSubmit must be passed as such to " + "the corresponding SubmissionFeedback"); } if (!editorTest) { StatisticalSubmissionInfo<S> toWrite = new StatisticalSubmissionInfo<>(submission .getTimeOnTask(), submission.getCorrectness(), System.currentTimeMillis(), submission .getSubmissionInfo()); StubDataFilesHandler.writeSubmToDisk(stubUsed, exerInfo.getName(), toWrite, tempMan); } SubmissionPopup sp = new SubmissionPopup(localizer, submission); getUI().addWindow(sp); }); } } @Override public void detach() { if (currentExecutor != null) { currentExecutor.shutdown(); } super.detach(); } }