tmf: Remove toString on string objects
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.analysis.xml.core / src / org / eclipse / tracecompass / internal / tmf / analysis / xml / core / module / XmlUtils.java
CommitLineData
e11e382c 1/*******************************************************************************
f98e9dbe 2 * Copyright (c) 2014, 2016 École Polytechnique de Montréal
e11e382c
FW
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 * Geneviève Bastien - Initial API and implementation
11 *******************************************************************************/
12
6eca054d 13package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module;
e11e382c 14
f98e9dbe
JCK
15import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
16
e11e382c
FW
17import java.io.File;
18import java.io.FileInputStream;
19import java.io.FileOutputStream;
20import java.io.IOException;
21import java.net.URL;
22import java.nio.channels.FileChannel;
0f7276b6 23import java.util.ArrayList;
f98e9dbe
JCK
24import java.util.Collections;
25import java.util.HashMap;
0f7276b6 26import java.util.List;
f98e9dbe 27import java.util.Map;
e11e382c
FW
28
29import javax.xml.XMLConstants;
6d20d989
GB
30import javax.xml.parsers.DocumentBuilder;
31import javax.xml.parsers.DocumentBuilderFactory;
32import javax.xml.parsers.ParserConfigurationException;
e11e382c
FW
33import javax.xml.transform.Source;
34import javax.xml.transform.stream.StreamSource;
35import javax.xml.validation.Schema;
36import javax.xml.validation.SchemaFactory;
37import javax.xml.validation.Validator;
38
39import org.eclipse.core.runtime.IPath;
40import org.eclipse.core.runtime.IStatus;
6d20d989 41import org.eclipse.core.runtime.Path;
e11e382c 42import org.eclipse.core.runtime.Status;
6d20d989 43import org.eclipse.jdt.annotation.NonNull;
4c4e2816 44import org.eclipse.jdt.annotation.Nullable;
e11e382c 45import org.eclipse.osgi.util.NLS;
2bdf0193 46import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
6eca054d 47import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
6d20d989 48import org.w3c.dom.Document;
0f7276b6
GB
49import org.w3c.dom.Element;
50import org.w3c.dom.Node;
51import org.w3c.dom.NodeList;
e11e382c
FW
52import org.xml.sax.SAXException;
53import org.xml.sax.SAXParseException;
54
55/**
56 * Class containing some utilities for the XML plug-in packages: for example, it
57 * manages the XML files and validates them
58 *
59 * @author Geneviève Bastien
60 */
61public class XmlUtils {
62
63 /** Sub-directory of the plug-in where XML files are stored */
64 private static final String XML_DIRECTORY = "xml_files"; //$NON-NLS-1$
65
66 /** Name of the XSD schema file */
f47f1bbe 67 private static final String XSD = "xmlDefinition.xsd"; //$NON-NLS-1$
e11e382c 68
f98e9dbe
JCK
69 /**
70 * Extension for XML files
71 * @since 2.0
72 */
537572cd 73 public static final String XML_EXTENSION = "xml"; //$NON-NLS-1$
f98e9dbe 74
e11e382c
FW
75 /** Make this class non-instantiable */
76 private XmlUtils() {
77
78 }
79
80 /**
81 * Get the path where the XML files are stored. Create it if it does not
82 * exist
83 *
84 * @return path to XML files
85 */
86 public static IPath getXmlFilesPath() {
87 IPath path = Activator.getDefault().getStateLocation();
88 path = path.addTrailingSeparator().append(XML_DIRECTORY);
89
90 /* Check if directory exists, otherwise create it */
91 File dir = path.toFile();
92 if (!dir.exists() || !dir.isDirectory()) {
93 dir.mkdirs();
94 }
95
96 return path;
97 }
98
99 /**
100 * Validate the XML file input with the XSD schema
101 *
102 * @param xmlFile
103 * XML file to validate
104 * @return True if the XML validates
105 */
106 public static IStatus xmlValidate(File xmlFile) {
107 URL url = XmlUtils.class.getResource(XSD);
108 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
109 Source xmlSource = new StreamSource(xmlFile);
110 try {
111 Schema schema = schemaFactory.newSchema(url);
112 Validator validator = schema.newValidator();
113 validator.validate(xmlSource);
114 } catch (SAXParseException e) {
115 String error = NLS.bind(Messages.XmlUtils_XmlParseError, e.getLineNumber(), e.getLocalizedMessage());
116 Activator.logError(error);
0f7276b6 117 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
e11e382c
FW
118 } catch (SAXException e) {
119 String error = NLS.bind(Messages.XmlUtils_XmlValidationError, e.getLocalizedMessage());
120 Activator.logError(error);
0f7276b6 121 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
e11e382c
FW
122 } catch (IOException e) {
123 String error = Messages.XmlUtils_XmlValidateError;
124 Activator.logError("IO exception occurred", e); //$NON-NLS-1$
0f7276b6 125 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
e11e382c
FW
126 }
127 return Status.OK_STATUS;
128 }
129
130 /**
131 * Adds an XML file to the plugin's path. The XML file should have been
132 * validated using the {@link XmlUtils#xmlValidate(File)} method before
133 * calling this method.
134 *
135 * @param fromFile
136 * The XML file to add
137 * @return Whether the file was successfully added
138 */
139 public static IStatus addXmlFile(File fromFile) {
140
141 /* Copy file to path */
142 File toFile = getXmlFilesPath().addTrailingSeparator().append(fromFile.getName()).toFile();
143
f98e9dbe
JCK
144 return copyXmlFile(fromFile, toFile);
145 }
146
147 /**
148 * List all files under the XML analysis files path. It returns a map where
149 * the key is the file name.
150 *
151 * @return A map with all the XML analysis files
152 * @since 2.0
153 */
537572cd
BH
154 public static synchronized @NonNull Map<String, File> listFiles() {
155 IPath pathToFiles = XmlUtils.getXmlFilesPath();
156 File folder = pathToFiles.toFile();
157
158 Map<String, File> fileMap = new HashMap<>();
159 if ((folder.isDirectory() && folder.exists())) {
cb11754a
JCK
160 File[] listOfFiles = folder.listFiles();
161 if (listOfFiles != null) {
162 for (File file : listOfFiles) {
163 IPath path = new Path(file.getName());
164 if (path.getFileExtension().equals(XML_EXTENSION)) {
165 fileMap.put(file.getName(), file);
166 }
537572cd 167 }
cb11754a
JCK
168 } else {
169 Activator.logError("I/O error occured while accessing files in folder " + folder.getPath()); //$NON-NLS-1$
537572cd 170 }
f98e9dbe 171 }
537572cd 172 return Collections.unmodifiableMap(fileMap);
f98e9dbe
JCK
173 }
174
175 /**
176 * Delete an XML analysis file
177 *
178 * @param name
179 * The XML file to delete
180 * @since 2.0
181 */
182 public static void deleteFile(String name) {
537572cd 183 Map<String, File> files = listFiles();
f98e9dbe
JCK
184 File file = files.get(name);
185 if (file == null) {
186 return;
187 }
188 file.delete();
189 }
190
191 /**
192 * Export an XML analysis file to an external path
193 *
194 * @param from
195 * The name of the file to export
196 * @param to
197 * The full path of the file to write to
198 * @return Whether the file was successfully exported
199 * @since 2.0
200 */
201 public static IStatus exportXmlFile(String from, String to) {
202
203 /* Copy file to path */
204 File fromFile = getXmlFilesPath().addTrailingSeparator().append(from).toFile();
205
206 if (!fromFile.exists()) {
207 Activator.logError("Failed to find XML analysis file " + fromFile.getName()); //$NON-NLS-1$
208 return Status.CANCEL_STATUS;
209 }
210
211 File toFile = new File(to);
212
213 return copyXmlFile(fromFile, toFile);
214 }
215
216 private static IStatus copyXmlFile(File fromFile, File toFile) {
e11e382c
FW
217 try {
218 if (!toFile.exists()) {
219 toFile.createNewFile();
220 }
221 } catch (IOException e) {
222 String error = Messages.XmlUtils_ErrorCopyingFile;
223 Activator.logError(error, e);
0f7276b6 224 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
e11e382c
FW
225 }
226
227 try (FileInputStream fis = new FileInputStream(fromFile);
228 FileOutputStream fos = new FileOutputStream(toFile);
229 FileChannel source = fis.getChannel();
230 FileChannel destination = fos.getChannel();) {
231 destination.transferFrom(source, 0, source.size());
232 } catch (IOException e) {
233 String error = Messages.XmlUtils_ErrorCopyingFile;
234 Activator.logError(error, e);
0f7276b6 235 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, error, e);
e11e382c
FW
236 }
237 return Status.OK_STATUS;
238 }
239
f98e9dbe
JCK
240 /**
241 * Get the IDs of all the analysis described in a single file
242 *
243 * @param fileName
244 * The file name
245 * @return The list of IDs
246 * @since 2.0
247 */
248 public static List<String> getAnalysisIdsFromFile(String fileName) {
249 List<String> ids = new ArrayList<>();
250 File file = getXmlFilesPath().addTrailingSeparator().append(fileName).toFile();
251 if (file.exists()) {
252 try {
253 /* Load the XML File */
254 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
255 DocumentBuilder dBuilder;
256 dBuilder = dbFactory.newDocumentBuilder();
257 Document doc = dBuilder.parse(file);
258 doc.getDocumentElement().normalize();
259
260 /* get State Providers modules */
261 NodeList stateproviderNodes = doc.getElementsByTagName(TmfXmlStrings.STATE_PROVIDER);
262 for (int i = 0; i < stateproviderNodes.getLength(); i++) {
263 ids.add(nullToEmptyString(((Element) stateproviderNodes.item(i)).getAttribute(TmfXmlStrings.ID)));
264 }
38e2a2e9
JCK
265
266 /* get patterns modules */
267 NodeList patternNodes = doc.getElementsByTagName(TmfXmlStrings.PATTERN);
268 for (int i = 0; i < patternNodes.getLength(); i++) {
269 ids.add(nullToEmptyString(((Element) patternNodes.item(i)).getAttribute(TmfXmlStrings.ID)));
270 }
f98e9dbe
JCK
271 } catch (ParserConfigurationException | SAXException | IOException e) {
272 Activator.logError("Failed to get analyses IDs from " + fileName); //$NON-NLS-1$
273 }
274 }
275 return ids;
276 }
277
0f7276b6
GB
278 /**
279 * Get only the XML element children of an XML element.
280 *
281 * @param parent
282 * The parent element to get children from
283 * @return The list of children Element of the parent
284 */
3a5f73a1 285 public static @NonNull List<@Nullable Element> getChildElements(Element parent) {
0f7276b6 286 NodeList childNodes = parent.getChildNodes();
4c4e2816 287 List<@Nullable Element> childElements = new ArrayList<>();
0f7276b6
GB
288 for (int index = 0; index < childNodes.getLength(); index++) {
289 if (childNodes.item(index).getNodeType() == Node.ELEMENT_NODE) {
290 childElements.add((Element) childNodes.item(index));
291 }
292 }
293 return childElements;
294 }
295
6d20d989
GB
296 /**
297 * Get the XML children element of an XML element, but only those of a
298 * certain type
299 *
300 * @param parent
301 * The parent element to get the children from
302 * @param elementTag
303 * The tag of the elements to return
304 * @return The list of children {@link Element} of the parent
305 */
4c4e2816 306 public static List<@NonNull Element> getChildElements(Element parent, String elementTag) {
6d20d989
GB
307 /* get the state providers and find the corresponding one */
308 NodeList nodes = parent.getElementsByTagName(elementTag);
4c4e2816 309 List<@NonNull Element> childElements = new ArrayList<>();
6d20d989
GB
310
311 for (int i = 0; i < nodes.getLength(); i++) {
312 Element node = (Element) nodes.item(i);
66471052
GB
313 if (node.getParentNode().equals(parent)) {
314 childElements.add(node);
315 }
6d20d989
GB
316 }
317 return childElements;
318 }
319
320 /**
321 * Return the node element corresponding to the requested type in the file.
322 *
323 * TODO: Nothing prevents from having duplicate type -> id in a same file.
324 * That should not be allowed. If you want an element with the same ID as
325 * another one, it should be in a different file and we should check it at
326 * validation time.
327 *
328 * @param filePath
329 * The absolute path to the XML file
330 * @param elementType
331 * The type of top level element to search for
332 * @param elementId
333 * The ID of the desired element
334 * @return The XML element or <code>null</code> if not found
335 */
336 public static Element getElementInFile(String filePath, @NonNull String elementType, @NonNull String elementId) {
337
338 if (filePath == null) {
339 return null;
340 }
341
342 IPath path = new Path(filePath);
343 File file = path.toFile();
344 if (file == null || !file.exists() || !file.isFile() || !xmlValidate(file).isOK()) {
345 return null;
346 }
347
348 try {
349 /* Load the XML File */
350 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
351 DocumentBuilder dBuilder;
352
353 dBuilder = dbFactory.newDocumentBuilder();
354 Document doc = dBuilder.parse(file);
355 doc.getDocumentElement().normalize();
356
357 /* get the state providers and find the corresponding one */
358 NodeList nodes = doc.getElementsByTagName(elementType);
359 Element foundNode = null;
360
361 for (int i = 0; i < nodes.getLength(); i++) {
362 Element node = (Element) nodes.item(i);
363 String id = node.getAttribute(TmfXmlStrings.ID);
364 if (id.equals(elementId)) {
365 foundNode = node;
366 }
367 }
368 return foundNode;
369 } catch (ParserConfigurationException | SAXException | IOException e) {
370 return null;
371 }
372
373 }
e11e382c 374}
This page took 0.081543 seconds and 5 git commands to generate.