package fi.utu.ville.exercises.stub; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.logging.Logger; import org.apache.commons.io.FileUtils; import com.vaadin.server.VaadinSession; import fi.utu.ville.exercises.model.ExerciseTypeDescriptor; /** * A class holding global-resources needed by the stub. The resource-links and other data are stored in {@link VaadinSession}-scope for simplicity. * * @author Riku Haavisto * */ class StubSessionData implements Serializable { /** * */ private static final long serialVersionUID = 5074154246188402009L; private static Logger logger = Logger.getLogger(StubSessionData.class .getName()); /** * @return current {@link StubSessionData}-instance */ public static StubSessionData getInstance() { return VaadinSession.getCurrent().getAttribute(StubSessionData.class); } /** * Initializes a new {@link StubSessionData} instance, if there is not already an instance stored to {@link VaadinSession}. * * @param typesToLoad * list of {@link ExerciseTypeDescriptor}s that will be present for testing in the stub * @param pathToResourceFiles * path of resource-files directory to use * @param localesToTest * list of {@link Locale}s that will be available for testing the localization of the exercise-type */ public static void initIfNeeded( List<ExerciseTypeDescriptor<?, ?>> typesToLoad, String pathToResourceFiles, List<Locale> localesToTest) { StubSessionData current = VaadinSession.getCurrent().getAttribute( StubSessionData.class); StubState.initIfNeeded(localesToTest.get(0), typesToLoad.get(0), StubExecutionSettings.values()[0]); if (current == null) { current = new StubSessionData(pathToResourceFiles, typesToLoad, localesToTest); VaadinSession.getCurrent().setAttribute(StubSessionData.class, current); } else if (!current.stubFilesBaseDir.equals(pathToResourceFiles)) { logger.warning("Stub-files base directory was changed from " + "'" + current.stubFilesBaseDir + "' to '" + pathToResourceFiles + "'. If you do not need the old files anymore, you " + "can manually remove the old directory!"); current = new StubSessionData(pathToResourceFiles, typesToLoad, localesToTest); VaadinSession.getCurrent().setAttribute(StubSessionData.class, current); } } /** * Constructs a new {@link StubSessionData}-object and initiates needed folder structure. * * @param filesBaseDir * base directory to which the stub data files are stored * @param typesToLoad * list of {@link ExerciseTypeDescriptor}s that will be present for testing in the stub * @param localesToTest * list of {@link Locale}s that will be available for testing the localization of the exercise-type */ private StubSessionData(String filesBaseDir, List<ExerciseTypeDescriptor<?, ?>> typesToLoad, List<Locale> localesToTest) { stubFilesBaseDir = filesBaseDir; if (typesToLoad == null || typesToLoad.isEmpty()) { throw new IllegalArgumentException("No types to load"); } if (localesToTest == null || localesToTest.isEmpty()) { throw new IllegalArgumentException( "No locales specified for testing"); } typesToTest = new ArrayList<ExerciseTypeDescriptor<?, ?>>( typesToLoad); this.localesToTest = new ArrayList<Locale>(localesToTest); initState(); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); // ensure that the needed directories still exist after // reloading the session initState(); } private final String stubFilesBaseDir; private final List<ExerciseTypeDescriptor<?, ?>> typesToTest; private final List<Locale> localesToTest; private transient boolean stateInited = false; private void testState() { if (!stateInited) { throw new IllegalStateException("State not initialized"); } } /** * @return list of {@link ExerciseTypeDescriptor} that are available for testing */ public List<ExerciseTypeDescriptor<?, ?>> getTypesToTest() { testState(); return typesToTest; } /** * @return a list of to make available for testing */ public List<Locale> getLocalesToTest() { testState(); return localesToTest; } /** * @return directory to use for stub's temporary files */ public String getStubExerMaterialsTempDir() { testState(); return getStubExerMaterialsTempDirPath(); } /** * Return the base directory to use for storing data-files to exercises of certain exercise-type. * * @param type * {@link ExerciseTypeDescriptor} for which to get the base directory * @return path of the correct base directory for certain exercise-type */ public String getTypeBaseDir(ExerciseTypeDescriptor<?, ?> type) { testState(); return stubFilesBaseDir + File.separatorChar + type.getClass().getSimpleName(); } /** * Clears everything inside the currently used temp-directory. */ public void clearTemp() { testState(); StubUtil.deleteDirectory(new File(getStubExerMaterialsTempDir()), false); } // private methods that do not test-state private String getTypeBaseFolderPath(ExerciseTypeDescriptor<?, ?> type) { return stubFilesBaseDir + File.separatorChar + type.getClass().getSimpleName(); } private String getStubExerMaterialsTempDirPath() { return stubFilesBaseDir + File.separatorChar + "temp"; } /** * Initiates the {@link StubSessionData}'s state by doing some tests and creating needed folders if they do not already exist. */ private void initState() { testForDuplicateDescriptors(typesToTest); testAndCreate(stubFilesBaseDir); testAndCreate(getStubExerMaterialsTempDirPath()); for (ExerciseTypeDescriptor<?, ?> type : typesToTest) { testAndCreate(getTypeBaseFolderPath(type)); } stateInited = true; } /** * Tests whether a directory exists in given path, and if it does not exists, attempts to create a directory to that path. * * @param path * path to test or create */ private static void testAndCreate(String path) { File testAndCreateFile = new File(path); if (!(testAndCreateFile.exists() && testAndCreateFile.isDirectory())) { try { FileUtils.forceMkdir(testAndCreateFile); } catch (IOException e) { throw new AssertionError( "Could not create a directory for storing exercise-type-stub-files. " + "Change the directory path or file permissions. " + "Tried to use directory: " + path); } } } /** * Tests that there are no duplicate simple-names for the descriptors as this would cause conflicts when using stub. * * @param typesToLoad * list of {@link ExerciseTypeDescriptor} to be loaded for the stub */ private static void testForDuplicateDescriptors( List<ExerciseTypeDescriptor<?, ?>> typesToLoad) { HashSet<String> allNames = new HashSet<String>(); for (ExerciseTypeDescriptor<?, ?> exerDesc : typesToLoad) { if (!allNames.add(exerDesc.getClass().getSimpleName())) { throw new IllegalArgumentException( "Duplicate 'simple-name' in" + " typeToLoad exerciseTypeDescriptor-list: " + exerDesc.getClass().getSimpleName() + ". This might not be " + "a real problem, but the stub relies on uniqueness of " + "the simple-names when saving needed files." ); } } } }