diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java index 44ed180d0901..42ae79931e43 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java @@ -19,6 +19,7 @@ import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; @@ -40,6 +41,7 @@ import static com.jetbrains.edu.learning.StudySerializationUtils.Xml.*; */ @State(name = "CCProjectService", storages = @Storage("course_service.xml")) public class CCProjectService implements PersistentStateComponent { + private static final Logger LOG = Logger.getInstance(CCProjectService.class); private Course myCourse; @Transient private final Project myProject; @@ -61,38 +63,45 @@ public class CCProjectService implements PersistentStateComponent { @Override public Element getState() { + if (myCourse == null) { + return null; + } return XmlSerializer.serialize(this); } @Override public void loadState(Element state) { - Element courseElement = getChildWithName(state, COURSE).getChild(COURSE_TITLED); - for (Element lesson : getChildList(courseElement, LESSONS)) { - int lessonIndex = getAsInt(lesson, INDEX); - for (Element task : getChildList(lesson, TASK_LIST)) { - int taskIndex = getAsInt(task, INDEX); - Map taskFiles = getChildMap(task, TASK_FILES); - for (Map.Entry entry : taskFiles.entrySet()) { - Element taskFileElement = entry.getValue(); - String name = entry.getKey(); - String answerName = FileUtil.getNameWithoutExtension(name) + CCUtils.ANSWER_EXTENSION_DOTTED + FileUtilRt.getExtension(name); - Document document = StudyUtils.getDocument(myProject.getBasePath(), lessonIndex, taskIndex, answerName); - if (document == null) { - continue; - } - for (Element placeholder : getChildList(taskFileElement, ANSWER_PLACEHOLDERS)) { - Element lineElement = getChildWithName(placeholder, LINE); - int line = lineElement != null ? Integer.valueOf(lineElement.getAttributeValue(VALUE)) : 0; - Element startElement = getChildWithName(placeholder, START); - int start = startElement != null ? Integer.valueOf(startElement.getAttributeValue(VALUE)) : 0; - int offset = document.getLineStartOffset(line) + start; - addChildWithName(placeholder, OFFSET, offset); - addChildWithName(placeholder, "useLength", "false"); + try { + Element courseElement = getChildWithName(state, COURSE).getChild(COURSE_TITLED); + for (Element lesson : getChildList(courseElement, LESSONS)) { + int lessonIndex = getAsInt(lesson, INDEX); + for (Element task : getChildList(lesson, TASK_LIST)) { + int taskIndex = getAsInt(task, INDEX); + Map taskFiles = getChildMap(task, TASK_FILES); + for (Map.Entry entry : taskFiles.entrySet()) { + Element taskFileElement = entry.getValue(); + String name = entry.getKey(); + String answerName = FileUtil.getNameWithoutExtension(name) + CCUtils.ANSWER_EXTENSION_DOTTED + FileUtilRt.getExtension(name); + Document document = StudyUtils.getDocument(myProject.getBasePath(), lessonIndex, taskIndex, answerName); + if (document == null) { + continue; + } + for (Element placeholder : getChildList(taskFileElement, ANSWER_PLACEHOLDERS)) { + Element lineElement = getChildWithName(placeholder, LINE); + int line = lineElement != null ? Integer.valueOf(lineElement.getAttributeValue(VALUE)) : 0; + Element startElement = getChildWithName(placeholder, START); + int start = startElement != null ? Integer.valueOf(startElement.getAttributeValue(VALUE)) : 0; + int offset = document.getLineStartOffset(line) + start; + addChildWithName(placeholder, OFFSET, offset); + addChildWithName(placeholder, "useLength", "false"); + } } } } + XmlSerializer.deserializeInto(this, state); + } catch (StudyUnrecognizedFormatException e) { + LOG.error(e); } - XmlSerializer.deserializeInto(this, state); } public static CCProjectService getInstance(@NotNull Project project) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java index 83b00b10d66b..cb4524aab5cb 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java @@ -16,11 +16,9 @@ import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jdom.Attribute; import org.jdom.Element; import org.jdom.output.XMLOutputter; -import org.jetbrains.annotations.Nullable; import java.io.File; import java.lang.reflect.Type; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -43,6 +41,8 @@ public class StudySerializationUtils { private StudySerializationUtils() { } + public static class StudyUnrecognizedFormatException extends Exception {} + public static class Xml { public final static String COURSE_ELEMENT = "courseElement"; public final static String MAIN_ELEMENT = "StudyTaskManager"; @@ -77,7 +77,7 @@ public class StudySerializationUtils { private Xml() { } - public static int getVersion(Element element) { + public static int getVersion(Element element) throws StudyUnrecognizedFormatException { if (element.getChild(COURSE_ELEMENT) != null) { return 1; } @@ -89,10 +89,10 @@ public class StudySerializationUtils { return -1; } - return Integer.valueOf(versionElement.getAttributeValue("value")); + return Integer.valueOf(versionElement.getAttributeValue(VALUE)); } - public static Element convertToSecondVersion(Element element) { + public static Element convertToSecondVersion(Element element) throws StudyUnrecognizedFormatException { final Element oldCourseElement = element.getChild(COURSE_ELEMENT); Element state = new Element(MAIN_ELEMENT); @@ -108,7 +108,7 @@ public class StudySerializationUtils { addChildWithName(authorElement, FIRST_NAME, names[0]); addChildWithName(authorElement, SECOND_NAME, names.length == 1 ? "" : names[1]); - addChildList(course, AUTHORS, Arrays.asList(authorElement)); + addChildList(course, AUTHORS, Collections.singletonList(authorElement)); Element courseDirectoryElement = getChildWithName(course, RESOURCE_PATH); renameElement(courseDirectoryElement, COURSE_DIRECTORY); @@ -138,7 +138,8 @@ public class StudySerializationUtils { return element; } - public static Map fillStatusMap(Element taskManagerElement, String mapName, XMLOutputter outputter) { + public static Map fillStatusMap(Element taskManagerElement, String mapName, XMLOutputter outputter) + throws StudyUnrecognizedFormatException { Map sourceMap = getChildMap(taskManagerElement, mapName); Map destMap = new HashMap<>(); for (Map.Entry entry : sourceMap.entrySet()) { @@ -151,7 +152,7 @@ public class StudySerializationUtils { return destMap; } - public static Element convertToThirdVersion(Element state, Project project) { + public static Element convertToThirdVersion(Element state, Project project) throws StudyUnrecognizedFormatException { Element taskManagerElement = state.getChild(MAIN_ELEMENT); XMLOutputter outputter = new XMLOutputter(); @@ -205,7 +206,7 @@ public class StudySerializationUtils { return taskStatus; } - public static void addInitialState(Document document, Element placeholder) { + public static void addInitialState(Document document, Element placeholder) throws StudyUnrecognizedFormatException { Element initialState = getChildWithName(placeholder, INITIAL_STATE).getChild(MY_INITIAL_STATE); int initialLine = getAsInt(initialState, MY_LINE); int initialStart = getAsInt(initialState, MY_START); @@ -214,18 +215,18 @@ public class StudySerializationUtils { renameElement(getChildWithName(initialState, MY_LENGTH), LENGTH); } - public static void addOffset(Document document, Element placeholder) { + public static void addOffset(Document document, Element placeholder) throws StudyUnrecognizedFormatException { int line = getAsInt(placeholder, LINE); int start = getAsInt(placeholder, START); int offset = document.getLineStartOffset(line) + start; addChildWithName(placeholder, OFFSET, offset); } - public static int getAsInt(Element element, String name) { + public static int getAsInt(Element element, String name) throws StudyUnrecognizedFormatException { return Integer.valueOf(getChildWithName(element, name).getAttributeValue(VALUE)); } - public static void incrementIndex(Element element) { + public static void incrementIndex(Element element) throws StudyUnrecognizedFormatException { Element index = getChildWithName(element, INDEX); int indexValue = Integer.parseInt(index.getAttributeValue(VALUE)); changeValue(index, indexValue + 1); @@ -263,7 +264,7 @@ public class StudySerializationUtils { return addChildWithName(parent, name, listElement); } - public static List getChildList(Element parent, String name) { + public static List getChildList(Element parent, String name) throws StudyUnrecognizedFormatException { Element listParent = getChildWithName(parent, name); if (listParent != null) { Element list = listParent.getChild(LIST); @@ -274,8 +275,7 @@ public class StudySerializationUtils { return Collections.emptyList(); } - @Nullable - public static Element getChildWithName(Element parent, String name) { + public static Element getChildWithName(Element parent, String name) throws StudyUnrecognizedFormatException { for (Element child : parent.getChildren()) { Attribute attribute = child.getAttribute(NAME); if (attribute == null) { @@ -285,10 +285,10 @@ public class StudySerializationUtils { return child; } } - return null; + throw new StudyUnrecognizedFormatException(); } - public static Map getChildMap(Element element, String name) { + public static Map getChildMap(Element element, String name) throws StudyUnrecognizedFormatException { Element mapParent = getChildWithName(element, name); if (mapParent != null) { Element map = mapParent.getChild(MAP); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java index 8b53f1ea7855..3dccfa46c3b3 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java @@ -17,6 +17,7 @@ import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.stepic.StepicUser; import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.jdom.Element; +import org.jdom.output.XMLOutputter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -113,43 +114,48 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb @Nullable @Override public Element getState() { - Element el = new Element("taskManager"); - if (myCourse != null) { - Element courseElement = new Element(StudySerializationUtils.Xml.MAIN_ELEMENT); - XmlSerializer.serializeInto(this, courseElement); - el.addContent(courseElement); + if (myCourse == null) { + return null; } + Element el = new Element("taskManager"); + Element courseElement = new Element(StudySerializationUtils.Xml.MAIN_ELEMENT); + XmlSerializer.serializeInto(this, courseElement); + el.addContent(courseElement); return el; } @Override public void loadState(Element state) { - int version = StudySerializationUtils.Xml.getVersion(state); - if (version == -1) { - LOG.error("StudyTaskManager doesn't contain any version:\n" + state.getValue()); - return; - } - switch (version) { - case 1: - state = StudySerializationUtils.Xml.convertToSecondVersion(state); - case 2: - state = StudySerializationUtils.Xml.convertToThirdVersion(state, myProject); - //uncomment for future versions - //case 3: - //state = StudySerializationUtils.Xml.convertToForthVersion(state, myProject); - } - - XmlSerializer.deserializeInto(this, state.getChild(StudySerializationUtils.Xml.MAIN_ELEMENT)); - VERSION = CURRENT_VERSION; - if (myCourse != null) { - myCourse.initCourse(true); - if (version != VERSION) { - String updatedCoursePath = FileUtil.join(PathManager.getConfigPath(), "courses", myCourse.getName()); - if (new File(updatedCoursePath).exists()) { - myCourse.setCourseDirectory(updatedCoursePath); + try { + int version = StudySerializationUtils.Xml.getVersion(state); + if (version == -1) { + LOG.error("StudyTaskManager doesn't contain any version:\n" + state.getValue()); + return; + } + switch (version) { + case 1: + state = StudySerializationUtils.Xml.convertToSecondVersion(state); + case 2: + state = StudySerializationUtils.Xml.convertToThirdVersion(state, myProject); + //uncomment for future versions + //case 3: + //state = StudySerializationUtils.Xml.convertToForthVersion(state, myProject); + } + XmlSerializer.deserializeInto(this, state.getChild(StudySerializationUtils.Xml.MAIN_ELEMENT)); + VERSION = CURRENT_VERSION; + if (myCourse != null) { + myCourse.initCourse(true); + if (version != VERSION) { + String updatedCoursePath = FileUtil.join(PathManager.getConfigPath(), "courses", myCourse.getName()); + if (new File(updatedCoursePath).exists()) { + myCourse.setCourseDirectory(updatedCoursePath); + } } } } + catch (StudySerializationUtils.StudyUnrecognizedFormatException e) { + LOG.error("Unexpected course format:\n", new XMLOutputter().outputString(state)); + } } public static StudyTaskManager getInstance(@NotNull final Project project) { @@ -187,7 +193,7 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb public void setTurnEditingMode(boolean turnEditingMode) { myTurnEditingMode = turnEditingMode; } - + public StepicUser getUser() { return myUser; }