private void saveSearchFile() { if (mySearch != null) { try { FileWriter fwriter = new FileWriter( ScilabConstants.SCIHOME.toString() + File.separator + getPersistentId() + ".xml"); BufferedWriter buffer = new BufferedWriter(fwriter); buffer.append("<SearchResults editor=\"" + editor.getUUID() + "\""); buffer.append(" base=\"" + mySearch.base + "\""); buffer.append(" recursive=\"" + mySearch.recursive + "\""); buffer.append(" ignoreCR=\"" + mySearch.ignoreCR + "\""); buffer.append( " filePattern=\"" + ScilabXMLUtilities.getXMLString(mySearch.filePattern) + "\""); buffer.append(" fileCaseSensitive=\"" + mySearch.fileCaseSensitive + "\""); if (mySearch.wordPattern != null && !mySearch.wordPattern.isEmpty()) { buffer.append( " wordPattern=\"" + ScilabXMLUtilities.getXMLString(mySearch.wordPattern) + "\""); } buffer.append(" wordCaseSensitive=\"" + mySearch.wordCaseSensitive + "\""); buffer.append(" wholeWord=\"" + mySearch.wholeWord + "\""); buffer.append(" regexp=\"" + mySearch.regexp + "\""); buffer.append(">\n"); mySearch.getResults().toXML(buffer, 1); buffer.append("</SearchResults>"); buffer.close(); } catch (Exception e) { e.printStackTrace(); } } }
/** * Class to retrieve object from the xml configuration file * * @author Calixte DENIZET */ public class XConfiguration { // User configuration file private static final String USER_CONFIG_FILE = ScilabConstants.SCIHOME.toString() + "/XConfiguration.xml"; private static final String SCI = System.getenv("SCI"); private static final String SCILAB_CONFIG_FILE = SCI + "/modules/preferences/etc/XConfiguration.xml"; private static final String ERROR_READ = Messages.gettext("Could not load file: "); private static final String ERROR_WRITE = Messages.gettext("Could not write the file: "); private static final String SEVERE_ERROR = Messages.gettext("A severe error occurred: cannot load the preferences file."); private static final String PARSING_ERROR = Messages.gettext( "An error occurred when loading the preferences file, try to reload the default one."); private static final XPathFactory xpathFactory = XPathFactory.newInstance(); private static final Map<Class<?>, StringParser> conv = new HashMap<Class<?>, StringParser>(); private static final EventListenerList listenerList = new EventListenerList(); private static final Set<String> modifiedPaths = new HashSet<String>(); private static Document doc; private static boolean hasBeenRead; static { addXConfigurationListener(ScilabGeneralPrefs.getInstance()); try { Class histoprefs = ClassLoader.getSystemClassLoader() .loadClass("org.scilab.modules.history_manager.HistoryPrefs"); Method getinstance = histoprefs.getDeclaredMethod("getInstance"); addXConfigurationListener((XConfigurationListener) getinstance.invoke(null)); } catch (ClassNotFoundException e) { // Nothing displayed (always occurs in MN mode) } catch (Exception e) { System.err.println(e); } } /** * Get the document in SCIHOME corresponding to the configuration file. * * @return the configuration document. */ public static Document getXConfigurationDocument() { if (doc == null) { boolean error = false; File xml = new File(USER_CONFIG_FILE); if (!xml.exists()) { ScilabXMLUtilities.writeDocument(createDocument(), USER_CONFIG_FILE); } DocumentBuilder docBuilder = null; try { DocumentBuilderFactory factory = ScilabDocumentBuilderFactory.newInstance(); docBuilder = factory.newDocumentBuilder(); doc = docBuilder.parse(xml); float version = getDocumentVersion(doc); float defaultVersion = getDocumentVersion(getDefaultDocument()); if (defaultVersion != version) { xml.delete(); doc = null; return getXConfigurationDocument(); } else { return doc; } } catch (ParserConfigurationException pce) { error = true; } catch (SAXException se) { error = true; } catch (IOException ioe) { error = true; } if (error) { if (hasBeenRead) { System.err.println(SEVERE_ERROR); doc = null; xml.delete(); return docBuilder.newDocument(); } hasBeenRead = true; doc = null; xml.delete(); System.err.println(PARSING_ERROR); return getXConfigurationDocument(); } return docBuilder.newDocument(); } return doc; } /** Save the modifications */ public static void writeDocument(String filename, Node written) { Transformer transformer = null; try { transformer = ScilabTransformerFactory.newInstance().newTransformer(); } catch (TransformerConfigurationException e1) { System.err.println(ERROR_WRITE + filename); return; } catch (TransformerFactoryConfigurationError e1) { System.err.println(ERROR_WRITE + filename); return; } transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StreamResult result = new StreamResult(new File(filename)); DOMSource source = new DOMSource(written); try { transformer.transform(source, result); } catch (TransformerException e) { System.err.println(ERROR_WRITE + filename); return; } // Invalidate the current document if (filename.equals(USER_CONFIG_FILE)) { doc = null; } } /** Save the modifications */ public static String dumpNode(Node written) { Transformer transformer = null; try { transformer = ScilabTransformerFactory.newInstance().newTransformer(); } catch (TransformerConfigurationException e1) { System.err.println("Cannot dump xml"); return ""; } catch (TransformerFactoryConfigurationError e1) { System.err.println("Cannot dump xml"); return ""; } transformer.setOutputProperty(OutputKeys.INDENT, "yes"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); StreamResult result = new StreamResult(new BufferedOutputStream(stream)); DOMSource source = new DOMSource(written); String str = ""; try { transformer.transform(source, result); str = stream.toString(); } catch (TransformerException e) { System.err.println("Cannot dump xml"); return str; } finally { try { stream.close(); } catch (Exception e) { } } return str; } /** * Get the document version * * @param doc the document * @return the version */ private static float getDocumentVersion(Document doc) { if (doc != null) { Element root = doc.getDocumentElement(); String version = root.getAttribute("version"); try { return Float.parseFloat(version); } catch (NumberFormatException e) { } } return 0.0f; } /** * Get the default document * * @return the document */ private static Document getDefaultDocument() { DocumentBuilder docBuilder; DocumentBuilderFactory factory; Document mainDoc = null; try { factory = ScilabDocumentBuilderFactory.newInstance(); docBuilder = factory.newDocumentBuilder(); mainDoc = docBuilder.parse(SCILAB_CONFIG_FILE); } catch (ParserConfigurationException pce) { System.err.println("Cannot create a XML DocumentBuilder:\n" + pce); return null; } catch (SAXException se) { System.err.println("Weird... Cannot parse basic file:\n" + se); return null; } catch (IOException ioe) { System.err.println("Weird... Cannot parse basic file:\n" + ioe); return null; } return mainDoc; } /** * Create a document in using the XConfiguration-*.xml found in SCI/modules/MODULE_NAME/etc/ * * @return the built document */ public static Document createDocument() { DocumentBuilder docBuilder; DocumentBuilderFactory factory; Document mainDoc = getDefaultDocument(); if (mainDoc == null) { return null; } Element root = mainDoc.getDocumentElement(); factory = ScilabDocumentBuilderFactory.newInstance(); try { docBuilder = factory.newDocumentBuilder(); } catch (ParserConfigurationException pce) { System.err.println("Cannot create a XML DocumentBuilder:\n" + pce); return null; } List<File> etcs = getEtcDir(); for (File etc : etcs) { File[] xmls = etc.listFiles( new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".xml") && name.startsWith("XConfiguration-"); } }); for (File xml : xmls) { try { Document doc = docBuilder.parse(xml); if (xml.getName().equals("XConfiguration-general.xml")) { try { XPath xp = xpathFactory.newXPath(); NodeList nodes = (NodeList) xp.compile( "//shortcuts/body/actions/action-folder/action[contains(@key, 'OSSCKEY')]") .evaluate(doc, XPathConstants.NODESET); for (int i = 0; i < nodes.getLength(); i++) { Element e = (Element) nodes.item(i); e.setAttribute( "key", e.getAttribute("key").replace("OSSCKEY", ScilabKeyStroke.getOSMetaKey())); } } catch (XPathExpressionException e) { System.err.println(e); } } Node node = mainDoc.importNode(doc.getDocumentElement(), true); NodeList list = root.getElementsByTagName(node.getNodeName()); if (list.getLength() != 0) { root.replaceChild(node, list.item(0)); } } catch (SAXException se) { System.err.println(ERROR_READ + xml.getName()); } catch (IOException ioe) { System.err.println(ERROR_READ + xml.getName()); } } } return mainDoc; } /** * Get a the list of the etc dirs in modules dirs * * @return the lit of etc dirs */ public static List<File> getEtcDir() { List<File> list = new ArrayList<File>(); File modulesDir = new File(SCI + "/modules/"); File[] modules = modulesDir.listFiles( new FileFilter() { public boolean accept(File f) { return f.isDirectory(); } }); for (File module : modules) { File etc = new File(module, "/etc/"); if (etc.exists() && etc.isDirectory()) { list.add(etc); } } return list; } public static void addModifiedPath(String path) { if (path != null && !path.isEmpty()) { modifiedPaths.add(path); } } public static void invalidate() { modifiedPaths.clear(); doc = null; } public static void addXConfigurationListener(XConfigurationListener listener) { listenerList.add(XConfigurationListener.class, listener); } public static void removeXConfigurationListener(XConfigurationListener listener) { listenerList.remove(XConfigurationListener.class, listener); } public static XConfigurationListener[] getXConfigurationListeners() { return listenerList.getListeners(XConfigurationListener.class); } public static void fireXConfigurationEvent() { if (!modifiedPaths.isEmpty()) { XConfigurationEvent event = null; Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == XConfigurationListener.class) { if (event == null) { event = new XConfigurationEvent(modifiedPaths); } ((XConfigurationListener) listeners[i + 1]).configurationChanged(event); } } modifiedPaths.clear(); } } /** * Register a StringParser for a given Class * * @param type the class type * @param parser the StringParser */ public static void registerStringParser(Class<?> type, StringParser parser) { conv.put(type, parser); } /** * Get a StringParser for a given Class * * @param type the class type * @return the corresponding parser */ public static StringParser getStringParser(Class<?> type) { return conv.get(type); } public static void set(final Document doc, final String path, String value) { XPath xp = xpathFactory.newXPath(); NodeList nodes; try { nodes = (NodeList) xp.compile(path).evaluate(doc, XPathConstants.NODESET); } catch (XPathExpressionException e) { System.err.println(e); return; } for (int i = 0; i < nodes.getLength(); i++) { Node n = nodes.item(i); if (n != null && n.getNodeType() == Node.ATTRIBUTE_NODE) { n.setNodeValue(value); } } writeDocument(USER_CONFIG_FILE, doc); } /** Save the current file */ public static void save() { if (doc != null) { writeDocument(USER_CONFIG_FILE, doc); } } /** * Get all the nodes with the given path. All the get nodes are serialized into an object (generic * paramater) which must have a constructor without argument and with methods named * set<Attribute Name> with one argument and no returned value. For example a node <foo * aaa="1" bbb="true" ccc-ddd="#001122"/> could be retrieved with something like * XConfiguration.get(MyObject.class, doc, "//path/to/node") where MyObject should be something * like <code> * public class MyObject { * * public MyObject() { * // ... * } * * public void setAaa(int a) { * // ... * } * * public void setBbb(boolean b) { * // ... * } * * public void setCccDdd(Color c) { * // ... * } * } * </code> If an attribute must not be retrieved, just remove the setter. * * <p>It is possible to use the annotation @XConfAttribute to make easier the retrievement. For * example <code> * @XConfAttribute * public class MyObject { * * public MyObject() { * // ... * } * * @XConfAttribute(attributes={"aaa", "bbb", "ccc-ddd"}) * // the contents of aaa will be converted into int and passed as first argument * // the contents of bbb will be converted into boolean and passed as second argument * // the contents of ccc-ddd will be converted into Color and passed as third argument * public void set(int n, boolean b, Color c) { * // ... * } * } * </code> * * @param type the Class type to retrieve * @param doc the document to explore * @param path the xpath query to retrieve the corresponding nodeset. * @return an array of instance of class type. */ public static final <T> T[] get(final Class<T> type, final Document doc, final String path) { XPath xp = xpathFactory.newXPath(); NodeList nodes; try { nodes = (NodeList) xp.compile(path).evaluate(doc, XPathConstants.NODESET); } catch (XPathExpressionException e) { System.err.println(e); return (T[]) Array.newInstance(type, 0); } if (type.getAnnotation(XConfAttribute.class) != null) { T[] arr = get(type, nodes); if (arr != null) { return arr; } } Method[] meths = type.getDeclaredMethods(); Map<String, Method> mapMethods = new HashMap<String, Method>(); for (Method m : meths) { String name = m.getName(); if (name.startsWith("set") && m.getParameterTypes().length == 1 && m.getReturnType().equals(Void.TYPE)) { mapMethods.put(m.getName(), m); m.setAccessible(true); } } Map<String, String> names = new HashMap<String, String>(); T[] values = (T[]) Array.newInstance(type, nodes.getLength()); for (int i = 0; i < values.length; i++) { NamedNodeMap map = nodes.item(i).getAttributes(); try { Constructor<T> constructor = type.getDeclaredConstructor(new Class[] {}); constructor.setAccessible(true); values[i] = constructor.newInstance(); } catch (InstantiationException e) { System.err.println(e); break; } catch (IllegalAccessException e) { System.err.println(e); break; } catch (NoSuchMethodException e) { System.err.println(e); break; } catch (InvocationTargetException e) { System.err.println(e.getTargetException()); } for (int j = 0; j < map.getLength(); j++) { Node n = map.item(j); String name = n.getNodeName(); String methName = names.get(name); if (methName == null) { StringBuilder buffer = new StringBuilder("set"); String[] parts = name.split("-"); for (String part : parts) { if (part != null && part.length() > 0) { buffer.append(part.substring(0, 1).toUpperCase()); buffer.append(part.substring(1).toLowerCase()); } } methName = buffer.toString(); names.put(name, methName); } String value = n.getNodeValue(); Method method = mapMethods.get(methName); if (method != null) { Class[] paramsClass = method.getParameterTypes(); StringParser parser = conv.get(paramsClass[0]); if (parser != null) { Object[] params = new Object[] {parser.parse(value)}; try { method.invoke(values[i], params); } catch (IllegalAccessException e) { System.err.println(e); } catch (IllegalArgumentException e) { System.err.println(e); } catch (InvocationTargetException e) { System.err.println(e.getTargetException()); } } } } } return values; } /** * Get a Map with where the key is the converted value (according to keyType) of the attribute * named key and the value is given in the same way. * * @param doc the document to read * @param key the attribute name where its value will be converted and used as a key in the map * @param keyType the Class of the key * @param value the attribute name where its value will be converted and used as a value in the * map * @param valueType the Class of the value * @return the corresponding map. */ public static final <T, U> Map<T, U> get( final Document doc, final String key, final Class<T> keyType, final String value, final Class<U> valueType, final String path) { XPath xp = xpathFactory.newXPath(); Map<T, U> map = new HashMap<T, U>(); NodeList nodes; try { nodes = (NodeList) xp.compile(path).evaluate(doc, XPathConstants.NODESET); } catch (XPathExpressionException e) { System.err.println(e); return map; } int len = nodes.getLength(); for (int i = 0; i < len; i++) { NamedNodeMap nmap = nodes.item(i).getAttributes(); Node k = nmap.getNamedItem(key); Node v = nmap.getNamedItem(value); if (k == null || v == null) { return map; } String kk = k.getNodeValue(); String vv = v.getNodeValue(); StringParser convK = conv.get(keyType); StringParser convV = conv.get(valueType); if (convK == null || convV == null) { return map; } map.put((T) convK.parse(kk), (U) convV.parse(vv)); } return map; } /** * Getter for annoted class (with @XConfAttribute) * * @param type the class type * @param nodes the nodes to read * @return an array of instances of type, if the class is annoted * with @XConfAttribute(isStatic=true), the returned array is empty. */ private static final <T> T[] get(final Class<T> type, NodeList nodes) { Method[] meths = type.getDeclaredMethods(); List<String[]> attrs = new ArrayList<String[]>(); List<Method> methods = new ArrayList<Method>(); Map<String[], Method> mapMethods = new HashMap<String[], Method>(); for (Method m : meths) { String name = m.getName(); Annotation ann = m.getAnnotation(XConfAttribute.class); if (ann != null) { String[] attributes = ((XConfAttribute) ann).attributes(); if (attributes.length == m.getParameterTypes().length) { m.setAccessible(true); attrs.add(attributes); methods.add(m); } else { return null; } } } Annotation ann = type.getAnnotation(XConfAttribute.class); boolean mustInstantiate = !((XConfAttribute) ann).isStatic(); T[] values = null; int len = nodes.getLength(); if (mustInstantiate) { values = (T[]) Array.newInstance(type, len); } for (int i = 0; i < len; i++) { NamedNodeMap map = nodes.item(i).getAttributes(); String nodeName = nodes.item(i).getNodeName(); if (mustInstantiate) { try { Constructor<T> constructor = type.getDeclaredConstructor(new Class[] {}); constructor.setAccessible(true); values[i] = constructor.newInstance(); } catch (InstantiationException e) { System.err.println(e); break; } catch (IllegalAccessException e) { System.err.println(e); break; } catch (NoSuchMethodException e) { System.err.println(e); break; } catch (InvocationTargetException e) { System.err.println(e.getTargetException()); } } for (int j = 0; j < methods.size(); j++) { Method method = methods.get(j); ann = method.getAnnotation(XConfAttribute.class); String tag = ((XConfAttribute) ann).tag(); if (tag.isEmpty() || tag.equals(nodeName)) { String[] attributes = attrs.get(j); Object[] params = new Object[attributes.length]; Class[] paramsClass = method.getParameterTypes(); for (int k = 0; k < attributes.length; k++) { String p = ""; Node node = null; if (map != null) { node = map.getNamedItem(attributes[k]); } if (node != null) { p = node.getNodeValue(); } StringParser parser = conv.get(paramsClass[k]); if (parser != null) { params[k] = parser.parse(p); } } try { if (mustInstantiate) { method.invoke(values[i], params); } else { method.invoke(null, params); } } catch (IllegalAccessException e) { System.err.println(e); } catch (IllegalArgumentException e) { System.err.println(e); } catch (InvocationTargetException e) { System.err.println(e.getTargetException()); } } } } if (mustInstantiate) { return values; } else { return (T[]) Array.newInstance(type, 0); } } /** Interface to implement to parse an attribute String into a Java object */ public static interface StringParser { /** * Parse a string * * @param str the string to parse * @return the corresponding Object */ public Object parse(String str); } static { conv.put( int.class, new StringParser() { public Integer parse(String str) { try { return Integer.parseInt(str); } catch (NumberFormatException e) { try { return (int) Double.parseDouble(str); } catch (NumberFormatException ee) { return new Integer(0); } } } }); conv.put( char.class, new StringParser() { public Object parse(String str) { if (str.length() > 0) { return str.charAt(0); } else { return new Character((char) 0); } } }); conv.put( byte.class, new StringParser() { public Object parse(String str) { try { return Byte.parseByte(str); } catch (NumberFormatException e) { try { return (byte) Double.parseDouble(str); } catch (NumberFormatException ee) { return new Byte((byte) 0); } } } }); conv.put( short.class, new StringParser() { public Object parse(String str) { try { return Short.parseShort(str); } catch (NumberFormatException e) { try { return (short) Double.parseDouble(str); } catch (NumberFormatException ee) { return new Short((short) 0); } } } }); conv.put( double.class, new StringParser() { public Object parse(String str) { try { return Double.parseDouble(str); } catch (NumberFormatException ee) { return new Double((double) 0); } } }); conv.put( float.class, new StringParser() { public Object parse(String str) { try { return Float.parseFloat(str); } catch (NumberFormatException ee) { return new Float((float) 0); } } }); conv.put( boolean.class, new StringParser() { public Object parse(String str) { return Boolean.parseBoolean(str); } }); conv.put( long.class, new StringParser() { public Object parse(String str) { try { return Long.parseLong(str); } catch (NumberFormatException e) { try { return (long) Double.parseDouble(str); } catch (NumberFormatException ee) { return new Long((long) 0); } } } }); conv.put( String.class, new StringParser() { public Object parse(String str) { return str; } }); conv.put( Color.class, new StringParser() { public Object parse(String str) { try { return Color.decode(str); } catch (NumberFormatException e) { return Color.BLACK; } } }); conv.put( KeyStroke.class, new StringParser() { public Object parse(String str) { String[] toks = str.split(" +"); StringBuilder buffer = new StringBuilder(); for (int i = 0; i < toks.length - 1; i++) { buffer.append(toks[i].toLowerCase()); buffer.append(" "); } buffer.append(toks[toks.length - 1].toUpperCase()); return KeyStroke.getKeyStroke(buffer.toString()); } }); } @Retention(RetentionPolicy.RUNTIME) public @interface XConfAttribute { /** * Map method arguments with attributes name For example, <code> * @XConfAttribute(tag="mytag", attributes={"a", "b"}) * void foo(String one, int tow) { ... } * </code> The value of attribute "a" is converted into a String and passed as "one" * argument,... */ public String[] attributes() default {""}; public String tag() default ""; /** Used to avoid object instanciation so the differents annotated methods must be static. */ public boolean isStatic() default false; } }