New Jide License
[indepmod/experimental.git] / IndependentModeler / src / cz / cvut / promod / services / projectService / localIO / ProjectFileLoader.java
blobc98c7364d516e1d0a017af7a16f40e744aadc6b6
1 package cz.cvut.promod.services.projectService.localIO;
3 import cz.cvut.promod.gui.ModelerModel;
4 import cz.cvut.promod.services.pluginLoaderService.utils.PluginLoadErrors;
5 import cz.cvut.promod.services.projectService.treeProjectNode.ProjectRoot;
6 import cz.cvut.promod.services.projectService.ProjectService;
7 import cz.cvut.promod.services.projectService.results.LoadProjectResult;
8 import cz.cvut.promod.services.projectService.results.ConfigurationDifference;
9 import cz.cvut.promod.services.ModelerSession;
10 import cz.cvut.promod.services.pluginLoaderService.utils.NotationSpecificPlugins;
11 import cz.cvut.promod.plugin.notationSpecificPlugIn.notation.Notation;
12 import cz.cvut.promod.plugin.notationSpecificPlugIn.module.Module;
13 import cz.cvut.promod.plugin.extension.Extension;
14 import cz.cvut.promod.resources.Resources;
16 import java.io.*;
17 import java.util.List;
18 import java.util.LinkedList;
20 import org.apache.log4j.Logger;
21 import org.w3c.dom.Document;
22 import org.w3c.dom.NodeList;
23 import org.w3c.dom.Node;
24 import org.w3c.dom.NamedNodeMap;
25 import org.xml.sax.SAXException;
27 import javax.xml.XMLConstants;
28 import javax.xml.parsers.DocumentBuilderFactory;
29 import javax.xml.parsers.DocumentBuilder;
30 import javax.xml.parsers.ParserConfigurationException;
31 import javax.xml.transform.Source;
32 import javax.xml.transform.dom.DOMSource;
33 import javax.xml.transform.stream.StreamSource;
34 import javax.xml.validation.Schema;
35 import javax.xml.validation.SchemaFactory;
36 import javax.xml.validation.Validator;
38 /**
39 * ProMod, master thesis project
40 * User: Petr Zverina, petr.zverina@gmail.com
41 * Date: 0:44:44, 11.11.2009
44 /**
45 * Project file loading functionality holder.
47 public class ProjectFileLoader {
49 private static final Logger LOG = Logger.getLogger(ProjectFileLoader.class);
51 /**
52 * Loads the project file.
54 * @param projectFile is the FS project file location
55 * @return an instance of LoadProjectResult class holding operation results
57 public static LoadProjectResult loadProjectFile(final File projectFile) {
58 if(!isValidFile(projectFile)){
59 return null;
62 final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
64 final InputStream schemaInputStream = ClassLoader.getSystemResourceAsStream(
65 Resources.CONFIG + Resources.PROJECT_XSD_FILE
69 final Schema schema;
70 final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
71 final Source source = new StreamSource(schemaInputStream);
72 try {
73 schema = schemaFactory.newSchema(source);
75 } catch (SAXException e) {
76 LOG.info("Skipping plugin definition file validation. Schema not found.");
77 return new LoadProjectResult(null, null);
80 LOG.info("Validating project file against xsd file.");
82 documentBuilderFactory.setNamespaceAware(true);
83 documentBuilderFactory.setValidating(false);
85 final Document document;
87 try {
88 final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
90 documentBuilder.setErrorHandler(new ProjectFileXmlErrorHandler());
92 document = documentBuilder.parse(projectFile);
94 final Validator validator = schema.newValidator();
96 validator.validate(new DOMSource(document));
98 } catch (ParserConfigurationException e) {
99 LOG.error("XML Parser configuration has failed.", e);
100 return new LoadProjectResult(null, null);
102 } catch (IOException e) {
103 LOG.error("An IO error has occurred when reading the project file.", e);
104 return new LoadProjectResult(null, null);
106 } catch (SAXException e) {
107 LOG.error("An SAX error has occurred when reading the project file.", e);
108 return new LoadProjectResult(null, null);
111 final List<ConfigurationDifference> messages = getConfigurationChanges(document);
112 final ProjectRoot projectRoot = new ProjectRoot(getProjectName(projectFile.getName()), projectFile.getParent());
114 return new LoadProjectResult(projectRoot, messages);
118 * Finds differences in actual ProMod configuration and the configuration loaded from the project file
119 * and stores this changes in list.
121 * @param document is the loaded DOM document of project file
123 * @return list containing all differences in configuration
125 private static List<ConfigurationDifference> getConfigurationChanges(final Document document) {
126 final List<ConfigurationDifference> messages = new LinkedList<ConfigurationDifference>();
128 final NodeList rootNodeList = document.getElementsByTagName(XmlConsts.ROOT_ELEMENT);
129 if(rootNodeList.getLength() != 1){
130 LOG.error("More than one (or missing) root node in project xml file.");
131 return null;
134 final Node rootNode = rootNodeList.item(0);
136 final NodeList nodeList = rootNode.getChildNodes();
138 for(int i = 0; i < nodeList.getLength(); i++){
139 final Node node = nodeList.item(i);
141 if(XmlConsts.BASIC_INFO_ELEMENT.equals(node.getNodeName())){
142 processBasicInfo(node, messages);
144 } else if(XmlConsts.CONFIGURATION_ELEMENT.equals(node.getNodeName())){
145 final NodeList congigurationNodes = node.getChildNodes();
147 for(int j = 0; j < congigurationNodes.getLength(); j++){
148 final Node configurationNode = congigurationNodes.item(j);
150 if(XmlConsts.PLUGINS_ELEMENT.equals(configurationNode.getNodeName())){
151 final NodeList pluginNodes = configurationNode.getChildNodes();
153 for(int k = 0; k < pluginNodes.getLength(); k++){
154 final Node pluginNode = pluginNodes.item(k);
156 if(XmlConsts.NOTATION_ELEMENT.equals(pluginNode.getNodeName())){
157 processNotationSpecificInfo(pluginNode, messages);
159 } else if(XmlConsts.EXTENSION_ELEMENT.equals(pluginNode.getNodeName())){
160 processExtensionSpecificInfo(pluginNode, messages);
166 break;
170 return messages;
174 * Finds and saves for future use all differences between actual ProMod configuration and the configuration loaded
175 * from a project file related to the extensions.
177 * @param pluginNode is the plugin node from the project file DOM
178 * @param messages is the list that collect all differences
180 private static void processExtensionSpecificInfo(final Node pluginNode, final List<ConfigurationDifference> messages) {
181 final NamedNodeMap notationAttributes = pluginNode.getAttributes();
182 final String extensionIdentifier = readAttribute(notationAttributes.getNamedItem(XmlConsts.IDENTIFIER_ATTRIBUTE));
183 final String extensionFullName = readAttribute(notationAttributes.getNamedItem(XmlConsts.FULL_NAME_ATTRIBUTE));
185 if(extensionIdentifier != null){
186 final Extension extension = ModelerSession.getExtensionService().getExtension(extensionIdentifier);
188 if(extension == null){
189 messages.add(new ConfigurationDifference(ConfigurationDifference.ChangeType.MISSING_EXTENSION, extensionIdentifier));
191 } else {
192 if(!extension.getName().equals(extensionFullName)){
193 messages.add(new ConfigurationDifference(
194 ConfigurationDifference.ChangeType.DIFFERENT_FULL_NAME, extensionFullName, extensionIdentifier)
199 } else {
200 // should never happened
201 LOG.error("Missing extension identifier info in the project file.");
207 * Finds and saves for future use all differences between actual ProMod configuration and the configuration loaded
208 * from a project file related to the notations and their modules.
210 * @param pluginNode is the plugin node from the project file DOM
211 * @param messages is the list that collect all differences
213 private static void processNotationSpecificInfo(final Node pluginNode, final List<ConfigurationDifference> messages) {
214 final NamedNodeMap notationAttributes = pluginNode.getAttributes();
215 final String notationIdentifier = readAttribute(notationAttributes.getNamedItem(XmlConsts.IDENTIFIER_ATTRIBUTE));
216 final String notationFullName = readAttribute(notationAttributes.getNamedItem(XmlConsts.FULL_NAME_ATTRIBUTE));
217 final String notationAbbreviation = readAttribute(notationAttributes.getNamedItem(XmlConsts.ABBREVIATION_ATTRIBUTE));
218 final String notationExtension = readAttribute(notationAttributes.getNamedItem(XmlConsts.EXTENSION_ATTRIBUTE));
220 if(notationIdentifier != null){
221 final NotationSpecificPlugins notationSpecificPlugins = ModelerSession.getNotationService().getNotationSpecificPlugins(notationIdentifier);
223 if(notationSpecificPlugins == null){
224 messages.add(new ConfigurationDifference(ConfigurationDifference.ChangeType.MISSING_NOTATION, notationIdentifier));
226 } else {
227 final Notation notation = notationSpecificPlugins.getNotation();
229 if(!notation.getFullName().equals(notationFullName)){ // the full name doesn't fit
230 messages.add(new ConfigurationDifference(
231 ConfigurationDifference.ChangeType.DIFFERENT_FULL_NAME, notationFullName, notationIdentifier)
234 if(!notation.getAbbreviation().equals(notationAbbreviation)){ // the abbreviation doesn't fit
235 messages.add(new ConfigurationDifference(
236 ConfigurationDifference.ChangeType.DIFFERENT_ABBREVIATION, notationAbbreviation, notationIdentifier)
239 if(!notation.getLocalIOController().getNotationFileExtension().equals(notationExtension)){ // the extension doesn't fit
240 messages.add(new ConfigurationDifference(
241 ConfigurationDifference.ChangeType.DIFFERENT_EXTENSION, notationExtension, notationIdentifier)
245 final NodeList nodes = pluginNode.getChildNodes();
246 for(int i = 0; i < nodes.getLength(); i++){
247 final Node moduleNode = nodes.item(i);
249 if(XmlConsts.MODULE_ELEMENT.equals(moduleNode.getNodeName())){
250 final NamedNodeMap moduleAttributes = moduleNode.getAttributes();
251 final String moduleIdentifier = readAttribute(moduleAttributes.getNamedItem(XmlConsts.IDENTIFIER_ATTRIBUTE));
253 if(moduleIdentifier != null){
254 final Module module = notationSpecificPlugins.getModule(moduleIdentifier);
256 if(module == null){
257 messages.add(new ConfigurationDifference(
258 ConfigurationDifference.ChangeType.MISSING_MODULE, moduleIdentifier, notationIdentifier)
261 } else {
262 // should never happened
263 LOG.error("Missing module identifier info in the project file.");
269 } else {
270 // should never happened
271 LOG.error("Missing notation identifier info in the project file.");
277 private static void processBasicInfo(final Node node, final List<ConfigurationDifference> messages) {
278 // not important for projects
279 // possible usage for special purposes
283 * Reads node's attribute.
285 * @param node is the attribute node
287 * @return value of the attribute it exists, null otherwise
289 private static String readAttribute(final Node node){
290 if(node != null){
291 return node.getNodeValue();
294 return null;
297 private static String getProjectName(final String fileName) {
298 return fileName.substring(0, fileName.lastIndexOf(ProjectService.FILE_EXTENSION_DELIMITER));
302 * Checks the basic validity of the project file.
304 * @param projectFile is the project file
306 * @return true if the project file is valid, false otherwise
308 private static boolean isValidFile(final File projectFile){
309 if(projectFile == null){
310 LOG.error("Undefined project file.");
311 return false;
314 if(!projectFile.exists()){
315 LOG.error("Not existing project file.");
316 return false;
319 if(!projectFile.canRead()){
320 LOG.error("NOt possible to read the project file.");
321 return false;
324 if(!projectFile.isFile()){
325 LOG.error("Project file is not a file.");
326 return false;
329 if(!projectFile.getName().endsWith(ProjectService.PROJECT_FILE_EXTENSION)){
330 LOG.error("Not a correct project file extension.");
331 return false;
334 return true;