Commit | Line | Data |
---|---|---|
500d5c41 GM |
1 | /********************************************************************** |
2 | * Copyright (c) 2014 École Polytechnique de Montréal | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * Guilliano Molaire - Initial API and implementation | |
11 | *********************************************************************/ | |
9bc60be7 | 12 | package org.eclipse.tracecompass.lttng2.control.core.session; |
500d5c41 GM |
13 | |
14 | import java.io.File; | |
15 | import java.io.IOException; | |
16 | import java.net.URL; | |
17 | import java.util.Set; | |
18 | ||
19 | import javax.xml.XMLConstants; | |
20 | import javax.xml.parsers.DocumentBuilder; | |
21 | import javax.xml.parsers.DocumentBuilderFactory; | |
22 | import javax.xml.parsers.ParserConfigurationException; | |
23 | import javax.xml.transform.OutputKeys; | |
24 | import javax.xml.transform.Source; | |
25 | import javax.xml.transform.Transformer; | |
26 | import javax.xml.transform.TransformerException; | |
27 | import javax.xml.transform.TransformerFactory; | |
28 | import javax.xml.transform.dom.DOMSource; | |
29 | import javax.xml.transform.stream.StreamResult; | |
30 | import javax.xml.transform.stream.StreamSource; | |
31 | import javax.xml.validation.Schema; | |
32 | import javax.xml.validation.SchemaFactory; | |
33 | import javax.xml.validation.Validator; | |
34 | ||
35 | import org.eclipse.core.runtime.IPath; | |
36 | import org.eclipse.core.runtime.IStatus; | |
37 | import org.eclipse.core.runtime.Status; | |
500d5c41 | 38 | import org.eclipse.osgi.util.NLS; |
9bc60be7 AM |
39 | import org.eclipse.tracecompass.internal.lttng2.control.core.Activator; |
40 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.IChannelInfo; | |
41 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.IDomainInfo; | |
42 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.IEventInfo; | |
43 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.ISessionInfo; | |
44 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceEnablement; | |
45 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceEventType; | |
46 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceLogLevel; | |
47 | import org.eclipse.tracecompass.internal.lttng2.control.core.model.TraceSessionState; | |
500d5c41 GM |
48 | import org.w3c.dom.Document; |
49 | import org.w3c.dom.Element; | |
50 | import org.xml.sax.SAXException; | |
51 | import org.xml.sax.SAXParseException; | |
52 | ||
53 | /** | |
54 | * Class for generating a session configuration file. A session configuration is | |
55 | * used to configure a trace session. It is a XML formatted file that contains | |
56 | * values defining the behavior of that specific trace session. | |
57 | * <p> | |
58 | * Kernel session configuration example: | |
59 | * | |
60 | * <pre> | |
61 | * {@code | |
62 | * <sessions> | |
63 | * <session> | |
64 | * <name>test_kernel</name> | |
65 | * <domains> | |
66 | * <domain> | |
67 | * <type>KERNEL</type> | |
68 | * <buffer_type>GLOBAL</buffer_type> | |
69 | * <channels> | |
70 | * <channel> | |
71 | * <name>channel0</name> | |
72 | * <enabled>false</enabled> | |
73 | * <overwrite_mode>DISCARD</overwrite_mode> | |
74 | * <subbuffer_size>262144</subbuffer_size> | |
75 | * <subbuffer_count>4</subbuffer_count> | |
76 | * <switch_timer_interval>0</switch_timer_interval> | |
77 | * <read_timer_interval>200000</read_timer_interval> | |
78 | * <output_type>SPLICE</output_type> | |
79 | * <tracefile_size>0</tracefile_size> | |
80 | * <tracefile_count>0</tracefile_count> | |
81 | * <live_timer_interval>0</live_timer_interval> | |
82 | * <events> | |
83 | * <event> | |
84 | * <enabled>true</enabled> | |
85 | * <type>SYSCALL</type> | |
86 | * </event> | |
87 | * <event> | |
88 | * <name>snd_soc_cache_sync</name> | |
89 | * <enabled>true</enabled> | |
90 | * <type>TRACEPOINT</type> | |
91 | * </event> | |
92 | * </events> | |
93 | * </channel> | |
94 | * </channels> | |
95 | * </domain> | |
96 | * </domains> | |
97 | * <started>false</started> | |
98 | * <output> | |
99 | * <consumer_output> | |
100 | * <enabled>true</enabled> | |
101 | * <destination> | |
102 | * <path>/home/user/lttng-traces/test_kernel</path> | |
103 | * </destination> | |
104 | * </consumer_output> | |
105 | * </output> | |
106 | * </session> | |
107 | * </sessions> | |
108 | * } | |
109 | * </pre> | |
110 | * | |
111 | * </p> | |
112 | * | |
113 | * @author Guilliano Molaire | |
500d5c41 GM |
114 | */ |
115 | public final class SessionConfigGenerator { | |
116 | ||
117 | /** The name of the session schema */ | |
118 | private static final String SESSION_XSD_FILENAME = "session.xsd"; //$NON-NLS-1$ | |
119 | ||
120 | /** The indent size used for the session configuration XML file */ | |
121 | private static final String INDENT_AMOUNT_PROPERTY_NAME = "{http://xml.apache.org/xslt}indent-amount"; //$NON-NLS-1$ | |
122 | private static final String INDENT_AMOUNT_PROPERTY_VALUE = "4"; //$NON-NLS-1$ | |
123 | ||
124 | /** | |
125 | * Private constructor. The class should not be instantiated. | |
126 | */ | |
127 | private SessionConfigGenerator() { | |
128 | } | |
129 | ||
130 | // --------------------------------------------------------- | |
131 | // Methods to generate session configuration files | |
132 | // --------------------------------------------------------- | |
133 | ||
134 | /** | |
135 | * Generates a session configuration file from a set of session information. | |
136 | * | |
137 | * @param sessions | |
138 | * The session informations | |
139 | * @param sessionFileDestination | |
140 | * The path of the locally saved session configuration file | |
141 | * @return The status of the session configuration generation | |
142 | */ | |
143 | public static IStatus generateSessionConfig(Set<ISessionInfo> sessions, IPath sessionFileDestination) { | |
144 | /* Parameters validation */ | |
145 | if (sessions == null || sessions.isEmpty()) { | |
146 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SessionConfigXML_InvalidSessionInfoList); | |
147 | } else if (sessionFileDestination == null) { | |
148 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SessionConfigXML_InvalidTraceSessionPath); | |
149 | } | |
150 | ||
151 | /* Generate the session configuration file */ | |
152 | try { | |
153 | Document sessionConfigDocument = generateSessionConfig(sessions); | |
154 | ||
155 | if (sessionConfigDocument != null) { | |
156 | saveSessionConfig(sessionConfigDocument, sessionFileDestination.toString()); | |
157 | } else { | |
158 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SessionConfigXML_SessionConfigGenerationError); | |
159 | } | |
160 | } catch (TransformerException | IllegalArgumentException | ParserConfigurationException e) { | |
161 | Activator.getDefault().logError("Error generating the session configuration file: " + sessionFileDestination.toString(), e); //$NON-NLS-1$ | |
162 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage()); | |
163 | } | |
164 | ||
165 | return Status.OK_STATUS; | |
166 | } | |
167 | ||
168 | /** | |
169 | * Generates a session configuration from a set of session informations. | |
170 | * | |
171 | * @param sessions | |
172 | * The session informations | |
173 | * @return The document with all session configuration nodes | |
174 | * @throws IllegalArgumentException | |
175 | * On an illegal argument inside sessions | |
176 | * @throws ParserConfigurationException | |
177 | * On an parser configuration error | |
178 | */ | |
179 | private static Document generateSessionConfig(Iterable<ISessionInfo> sessions) throws IllegalArgumentException, ParserConfigurationException { | |
180 | DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); | |
181 | DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); | |
182 | ||
183 | Document document = docBuilder.newDocument(); | |
184 | ||
185 | Element rootElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_SESSIONS); | |
186 | document.appendChild(rootElement); | |
187 | ||
188 | for (ISessionInfo session : sessions) { | |
189 | /* All elements under "sessions" elements */ | |
190 | Element sessionElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_SESSION); | |
191 | ||
192 | /* Contents of session element */ | |
193 | String enabled = session.getSessionState().equals(TraceSessionState.ACTIVE) ? SessionConfigStrings.CONFIG_STRING_TRUE : SessionConfigStrings.CONFIG_STRING_FALSE; | |
194 | ||
195 | addElementContent(document, sessionElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, session.getName()); | |
196 | addElementContent(document, sessionElement, SessionConfigStrings.CONFIG_ELEMENT_STARTED, enabled); | |
197 | ||
198 | if (session.isSnapshotSession()) { | |
199 | /* If it's a snapshot, we must add an attribute telling it is */ | |
200 | Element attributesElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_ATTRIBUTES); | |
201 | addElementContent(document, attributesElement, SessionConfigStrings.CONFIG_ELEMENT_SNAPSHOT_MODE, SessionConfigStrings.CONFIG_STRING_TRUE); | |
202 | sessionElement.appendChild(attributesElement); | |
203 | } | |
204 | ||
205 | sessionElement.appendChild(getDomainsElement(document, session)); | |
206 | sessionElement.appendChild(getOutputElement(document, session)); | |
207 | rootElement.appendChild(sessionElement); | |
208 | } | |
209 | ||
210 | return document; | |
211 | } | |
212 | ||
213 | // --------------------------------------------------------- | |
214 | // Getters for each element of the configuration file | |
215 | // --------------------------------------------------------- | |
216 | ||
217 | /** | |
218 | * Gets the 'domains' element after creating it. | |
219 | * | |
220 | * @param document | |
221 | * The document in which the nodes are being added | |
222 | * @param session | |
223 | * The session informations | |
224 | * @return The domains element as an XML element | |
225 | */ | |
226 | private static Element getDomainsElement(Document document, ISessionInfo session) { | |
227 | Element domainsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_DOMAINS); | |
228 | ||
229 | for (IDomainInfo domain : session.getDomains()) { | |
230 | Element domainElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_DOMAIN); | |
231 | ||
232 | /* | |
233 | * Add everything specific to a domain | |
234 | * | |
235 | * TODO: We suppose here that domain is either kernel or UST. It | |
236 | * will have to change if other domains are supported | |
237 | */ | |
238 | String domainType = domain.isKernel() ? SessionConfigStrings.CONFIG_DOMAIN_TYPE_KERNEL : SessionConfigStrings.CONFIG_DOMAIN_TYPE_UST; | |
239 | addElementContent(document, domainElement, SessionConfigStrings.CONFIG_ELEMENT_TYPE, domainType); | |
240 | ||
241 | String bufferType = null; | |
242 | switch (domain.getBufferType()) { | |
243 | case BUFFER_PER_UID: | |
244 | bufferType = SessionConfigStrings.CONFIG_BUFFER_TYPE_PER_UID; | |
245 | break; | |
246 | case BUFFER_PER_PID: | |
247 | bufferType = SessionConfigStrings.CONFIG_BUFFER_TYPE_PER_PID; | |
248 | break; | |
249 | case BUFFER_SHARED: | |
250 | bufferType = SessionConfigStrings.CONFIG_BUFFER_TYPE_GLOBAL; | |
251 | break; | |
252 | case BUFFER_TYPE_UNKNOWN: | |
253 | default: | |
254 | throw new IllegalArgumentException(Messages.SessionConfigXML_UnknownDomainBufferType); | |
255 | } | |
256 | addElementContent(document, domainElement, SessionConfigStrings.CONFIG_ELEMENT_DOMAIN_BUFFER_TYPE, bufferType); | |
257 | ||
258 | /* Add the channels */ | |
259 | domainElement.appendChild(getChannelsElement(document, domain.isKernel(), domain.getChannels())); | |
260 | domainsElement.appendChild(domainElement); | |
261 | } | |
262 | ||
263 | return domainsElement; | |
264 | } | |
265 | ||
266 | /** | |
267 | * Gets the 'output' element after creating it. If the session is a | |
268 | * snapshot, it will be composed of a snapshot outputs element. Otherwise, | |
269 | * it will contain the consumer output element. | |
270 | * | |
271 | * @param document | |
272 | * The document in which the nodes are being added | |
273 | * @param session | |
274 | * The session informations | |
275 | * @return The output element as an XML node | |
276 | */ | |
277 | private static Element getOutputElement(Document document, ISessionInfo session) { | |
278 | Element outputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_OUTPUT); | |
279 | ||
280 | if (session.isSnapshotSession()) { | |
281 | outputElement.appendChild(getSnapshotOuputsElement(document, session)); | |
282 | } else if (session.isStreamedTrace()) { | |
283 | outputElement.appendChild(getNetOutputElement(document, session)); | |
284 | } else { | |
285 | outputElement.appendChild(getConsumerOutputElement(document, session)); | |
286 | } | |
287 | ||
288 | return outputElement; | |
289 | } | |
290 | ||
291 | /** | |
292 | * Gets the 'channels' element after creating it. | |
293 | * | |
294 | * @param document | |
295 | * The document in which the nodes are being added | |
296 | * @param isKernel | |
297 | * Is it a kernel domain type | |
298 | * @param channels | |
299 | * The channels to be added as elements | |
300 | * @return The channels element as an XML element | |
301 | */ | |
302 | private static Element getChannelsElement(Document document, boolean isKernel, IChannelInfo[] channels) { | |
303 | Element channelsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_CHANNELS); | |
304 | ||
305 | for (IChannelInfo channel : channels) { | |
306 | Element channelElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_CHANNEL); | |
307 | ||
308 | /* Add everything related to a channel */ | |
309 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, channel.getName()); | |
310 | ||
311 | String overwriteMode = channel.isOverwriteMode() ? SessionConfigStrings.CONFIG_OVERWRITE_MODE_OVERWRITE : SessionConfigStrings.CONFIG_OVERWRITE_MODE_DISCARD; | |
312 | String enabled = channel.getState().equals(TraceEnablement.ENABLED) ? SessionConfigStrings.CONFIG_STRING_TRUE : SessionConfigStrings.CONFIG_STRING_FALSE; | |
313 | ||
314 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_ENABLED, enabled); | |
315 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_OVERWRITE_MODE, overwriteMode); | |
316 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_SUBBUFFER_SIZE, channel.getSubBufferSize()); | |
317 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_SUBBUFFER_COUNT, channel.getNumberOfSubBuffers()); | |
318 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_SWITCH_TIMER_INTERVAL, channel.getSwitchTimer()); | |
319 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_READ_TIMER_INTERVAL, channel.getReadTimer()); | |
320 | ||
0ad9fc89 | 321 | String outputType = channel.getOutputType().getInName().startsWith(SessionConfigStrings.CONFIG_OUTPUT_TYPE_MMAP) ? |
500d5c41 GM |
322 | outputType = SessionConfigStrings.CONFIG_OUTPUT_TYPE_MMAP : SessionConfigStrings.CONFIG_OUTPUT_TYPE_SPLICE; |
323 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_OUTPUT_TYPE, outputType); | |
324 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_TRACEFILE_SIZE, channel.getMaxSizeTraceFiles()); | |
325 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_TRACEFILE_COUNT, channel.getMaxNumberTraceFiles()); | |
326 | ||
327 | /* | |
328 | * TODO: Replace the 0 value by the channel live timer property from | |
329 | * SessionInfo once live session tracing is supported | |
330 | */ | |
331 | addElementContent(document, channelElement, SessionConfigStrings.CONFIG_ELEMENT_LIVE_TIMER_INTERVAL, SessionConfigStrings.CONFIG_STRING_ZERO); | |
332 | ||
333 | /* Add the events */ | |
334 | channelElement.appendChild(getEventsElement(document, isKernel, channel.getEvents())); | |
335 | channelsElement.appendChild(channelElement); | |
336 | } | |
337 | ||
338 | return channelsElement; | |
339 | } | |
340 | ||
341 | /** | |
342 | * Gets the 'events' element after creating it. It is composed of the event | |
343 | * informations from a list of IEventInfo. | |
344 | * | |
345 | * @param document | |
346 | * The document in which the nodes are being added | |
347 | * @param isKernel | |
348 | * Is the domain type kernel | |
349 | * @param events | |
350 | * The event informations to be added | |
351 | * @return An element containing all the event informations as XML elements | |
352 | */ | |
353 | private static Element getEventsElement(Document document, boolean isKernel, IEventInfo[] events) { | |
354 | Element eventsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_EVENTS); | |
355 | ||
356 | for (IEventInfo event : events) { | |
357 | Element eventElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_EVENT); | |
358 | ||
359 | /* Enabled attribute */ | |
360 | String enabled = event.getState().equals(TraceEnablement.ENABLED) ? SessionConfigStrings.CONFIG_STRING_TRUE : SessionConfigStrings.CONFIG_STRING_FALSE; | |
361 | ||
362 | /* Add the attributes to the event node */ | |
363 | addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, event.getName()); | |
364 | addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_ENABLED, enabled); | |
365 | TraceEventType eventType = event.getEventType(); | |
366 | if (!eventType.equals(TraceEventType.UNKNOWN)) { | |
367 | addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_TYPE, eventType.getInName().toUpperCase()); | |
368 | } else { | |
369 | throw new IllegalArgumentException(Messages.SessionConfigXML_UnknownEventType); | |
370 | } | |
371 | ||
372 | /* Specific to UST session config: the log level */ | |
373 | if (!isKernel && !event.getLogLevel().equals(TraceLogLevel.LEVEL_UNKNOWN)) { | |
374 | addElementContent(document, eventElement, SessionConfigStrings.CONFIG_ELEMENT_LOGLEVEL, event.getLogLevel().ordinal()); | |
375 | } | |
376 | ||
377 | /* Add the node to the parent node events */ | |
378 | eventsElement.appendChild(eventElement); | |
379 | } | |
380 | ||
381 | return eventsElement; | |
382 | } | |
383 | ||
384 | /** | |
385 | * Gets the 'consumer_output' element after creating it. | |
386 | * | |
387 | * @param document | |
388 | * The document in which the nodes are being added | |
389 | * @param session | |
390 | * The session informations | |
391 | * @return The consumer output element with his informations as XML elements | |
392 | */ | |
393 | private static Element getConsumerOutputElement(Document document, ISessionInfo session) { | |
394 | Element consumerOutputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_CONSUMER_OUTPUT); | |
395 | Element destinationElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_DESTINATION); | |
396 | ||
397 | /* Value of consumer output element */ | |
398 | addElementContent(document, consumerOutputElement, SessionConfigStrings.CONFIG_ELEMENT_ENABLED, SessionConfigStrings.CONFIG_STRING_TRUE); | |
399 | ||
400 | if (session.isStreamedTrace()) { | |
401 | /* If it is a streamed session, add the net output element */ | |
402 | destinationElement.appendChild(getNetOutputElement(document, session)); | |
403 | } else { | |
404 | addElementContent(document, destinationElement, SessionConfigStrings.CONFIG_ELEMENT_PATH, session.getSessionPath()); | |
405 | } | |
406 | ||
407 | consumerOutputElement.appendChild(destinationElement); | |
408 | return consumerOutputElement; | |
409 | } | |
410 | ||
411 | /** | |
412 | * Gets the 'net_output' element after creating it. It is composed of the | |
413 | * control and data URIs. | |
414 | * | |
415 | * @param document | |
416 | * The document in which the nodes are being added | |
417 | * @param session | |
418 | * The session informations | |
419 | * @return The net output element | |
420 | */ | |
421 | private static Element getNetOutputElement(Document document, ISessionInfo session) { | |
422 | Element netOutputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_NET_OUTPUT); | |
423 | ||
424 | String networkUrl = session.getNetworkUrl(); | |
425 | String controlUri = networkUrl == null ? session.getControlUrl() : networkUrl; | |
426 | String dataUri = networkUrl == null ? session.getDataUrl() : networkUrl; | |
427 | addElementContent(document, netOutputElement, SessionConfigStrings.CONFIG_ELEMENT_CONTROL_URI, controlUri); | |
428 | addElementContent(document, netOutputElement, SessionConfigStrings.CONFIG_ELEMENT_DATA_URI, dataUri); | |
429 | ||
430 | return netOutputElement; | |
431 | } | |
432 | ||
433 | /** | |
434 | * Gets the 'snapshot_outputs' element after creating it. | |
435 | * | |
436 | * @param document | |
437 | * The document in which the nodes are being added | |
438 | * @param session | |
439 | * The session informations | |
440 | * @return The snapshot outputs element with snapshot informations as XML | |
441 | * elements | |
442 | */ | |
443 | private static Element getSnapshotOuputsElement(Document document, ISessionInfo session) { | |
444 | Element snapshotOutputsElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_SNAPSHOT_OUTPUTS); | |
445 | Element outputElement = document.createElement(SessionConfigStrings.CONFIG_ELEMENT_OUTPUT); | |
446 | ||
447 | /* Add the name of the snapshot and the max size element */ | |
448 | addElementContent(document, outputElement, SessionConfigStrings.CONFIG_ELEMENT_NAME, session.getSnapshotInfo().getName()); | |
449 | ||
450 | /* | |
451 | * TODO: find the proper max size value of output element. For now it is | |
452 | * set to the default 0 value which means unlimited for lttng. | |
453 | */ | |
454 | addElementContent(document, outputElement, SessionConfigStrings.CONFIG_ELEMENT_MAX_SIZE, SessionConfigStrings.CONFIG_STRING_ZERO); | |
455 | outputElement.appendChild(getConsumerOutputElement(document, session)); | |
456 | ||
457 | snapshotOutputsElement.appendChild(outputElement); | |
458 | return snapshotOutputsElement; | |
459 | } | |
460 | ||
461 | // --------------------------------------------------------- | |
462 | // Utilities | |
463 | // --------------------------------------------------------- | |
464 | ||
465 | /** | |
466 | * Validates the session configuration file against its schema. | |
467 | * | |
468 | * @param sessionFile | |
469 | * The session configuration file | |
470 | * @return The status of the validation | |
471 | */ | |
472 | public static IStatus sessionValidate(File sessionFile) { | |
473 | URL url = SessionConfigGenerator.class.getResource(SESSION_XSD_FILENAME); | |
474 | SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); | |
475 | Source xmlSource = new StreamSource(sessionFile); | |
476 | ||
477 | try { | |
478 | Schema schema = schemaFactory.newSchema(url); | |
479 | Validator validator = schema.newValidator(); | |
480 | validator.validate(xmlSource); | |
481 | } catch (SAXParseException e) { | |
482 | String error = NLS.bind(Messages.SessionConfigXML_XmlParseError, e.getLineNumber(), e.getLocalizedMessage()); | |
483 | Activator.getDefault().logError(error); | |
484 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e); | |
485 | } catch (SAXException e) { | |
486 | String error = NLS.bind(Messages.SessionConfigXML_XmlValidationError, e.getLocalizedMessage()); | |
487 | Activator.getDefault().logError(error); | |
488 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e); | |
489 | } catch (IOException e) { | |
490 | String error = Messages.SessionConfigXML_XmlValidateError; | |
491 | Activator.getDefault().logError("IO exception occurred", e); //$NON-NLS-1$ | |
492 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e); | |
493 | } | |
494 | return Status.OK_STATUS; | |
495 | } | |
496 | ||
497 | /** | |
498 | * Saves the session configuration into a XML file. | |
499 | * | |
500 | * @param document | |
501 | * The document representing the session configuration file | |
502 | * @param destination | |
503 | * The path of the locally saved session configuration file | |
504 | * @throws TransformerException | |
505 | * On an transformation process | |
506 | */ | |
507 | private static void saveSessionConfig(Document document, String destination) throws TransformerException { | |
508 | /* Write the content into a XML file */ | |
509 | TransformerFactory transformerFactory = TransformerFactory.newInstance(); | |
510 | Transformer transformer = transformerFactory.newTransformer(); | |
511 | ||
512 | transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ | |
513 | transformer.setOutputProperty(INDENT_AMOUNT_PROPERTY_NAME, INDENT_AMOUNT_PROPERTY_VALUE); | |
514 | ||
515 | DOMSource source = new DOMSource(document); | |
516 | StreamResult result = new StreamResult(new File(destination)); | |
517 | ||
518 | transformer.transform(source, result); | |
519 | } | |
520 | ||
521 | /** | |
522 | * Adds to a parent node an element with his content. | |
523 | * | |
524 | * @param document | |
525 | * The document in which the nodes are being added | |
526 | * @param parent | |
527 | * The parent node that contains the element and his content | |
528 | * @param elementName | |
529 | * The element container name | |
530 | * @param elementContent | |
531 | * The content itself | |
532 | */ | |
533 | private static void addElementContent(Document document, Element parent, String elementName, Object elementContent) { | |
534 | Element contentElement = document.createElement(elementName); | |
535 | contentElement.appendChild(document.createTextNode(elementContent.toString())); | |
536 | parent.appendChild(contentElement); | |
537 | } | |
538 | } |