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
;
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
;
39 * ProMod, master thesis project
40 * User: Petr Zverina, petr.zverina@gmail.com
41 * Date: 0:44:44, 11.11.2009
45 * Project file loading functionality holder.
47 public class ProjectFileLoader
{
49 private static final Logger LOG
= Logger
.getLogger(ProjectFileLoader
.class);
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
)){
62 final DocumentBuilderFactory documentBuilderFactory
= DocumentBuilderFactory
.newInstance();
64 final InputStream schemaInputStream
= ClassLoader
.getSystemResourceAsStream(
65 Resources
.CONFIG
+ Resources
.PROJECT_XSD_FILE
70 final SchemaFactory schemaFactory
= SchemaFactory
.newInstance(XMLConstants
.W3C_XML_SCHEMA_NS_URI
);
71 final Source source
= new StreamSource(schemaInputStream
);
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
;
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.");
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
);
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
));
192 if(!extension
.getName().equals(extensionFullName
)){
193 messages
.add(new ConfigurationDifference(
194 ConfigurationDifference
.ChangeType
.DIFFERENT_FULL_NAME
, extensionFullName
, extensionIdentifier
)
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
));
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
);
257 messages
.add(new ConfigurationDifference(
258 ConfigurationDifference
.ChangeType
.MISSING_MODULE
, moduleIdentifier
, notationIdentifier
)
262 // should never happened
263 LOG
.error("Missing module identifier info in the project file.");
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
){
291 return node
.getNodeValue();
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.");
314 if(!projectFile
.exists()){
315 LOG
.error("Not existing project file.");
319 if(!projectFile
.canRead()){
320 LOG
.error("NOt possible to read the project file.");
324 if(!projectFile
.isFile()){
325 LOG
.error("Project file is not a file.");
329 if(!projectFile
.getName().endsWith(ProjectService
.PROJECT_FILE_EXTENSION
)){
330 LOG
.error("Not a correct project file extension.");