/* * Author: Markus Barchfeld * * Copyright (c) 2005 RubyPeople. * * This file is part of the Ruby Development Tools (RDT) plugin for eclipse. RDT is * subject to the "Common Public License (CPL) v 1.0". You may not use RDT except in * compliance with the License. For further information see org.rubypeople.rdt/rdt.license. * This file is based on org.eclipse.jface.text.templates.persistence.TemplateReaderWriter * / /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.rubypeople.rdt.internal.debug.ui.evaluation; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.jface.text.Assert; import org.rubypeople.rdt.internal.debug.ui.RdtDebugUiMessages; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Serializes templates as character or byte stream and reads the same format * back. Clients may instantiate this class, it is not intended to be * subclassed. * * @since 3.0 */ public class EvaluationExpressionReaderWriter { private static final String TEMPLATE_ROOT = "expressions"; //$NON-NLS-1$ private static final String TEMPLATE_ELEMENT = "expression"; //$NON-NLS-1$ private static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$ private static final String DESCRIPTION_ATTRIBUTE = "description"; //$NON-NLS-1$ private static final String ENABLED_ATTRIBUTE = "enabled"; //$NON-NLS-1$ /** * Create a new instance. */ public EvaluationExpressionReaderWriter() {} /** * Reads templates from a reader and returns them. The reader must present a * serialized form as produced by the <code>save</code> method. * * @param reader * the reader to read templates from * @return the read templates, encapsulated in instances of * <code>TemplatePersistenceData</code> * @throws IOException * if reading from the stream fails */ public EvaluationExpression[] read(Reader reader) throws IOException { return read(reader, null); } /** * Reads templates from a stream and adds them to the templates. * * @param reader * the reader to read templates from * @param bundle * a resource bundle to use for translating the read templates, * or <code>null</code> if no translation should occur * @return the read templates, encapsulated in instances of * <code>TemplatePersistenceData</code> * @throws IOException * if reading from the stream fails */ public EvaluationExpression[] read(Reader reader, ResourceBundle bundle) throws IOException { return read(new InputSource(reader), bundle); } public EvaluationExpression[] read(InputStream stream, ResourceBundle bundle) throws IOException { return read(new InputSource(stream), bundle); } private EvaluationExpression[] read(InputSource source, ResourceBundle bundle) throws IOException { try { Collection expressions = new ArrayList(); Set ids = new HashSet(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = factory.newDocumentBuilder(); Document document = parser.parse(source); NodeList elements = document.getElementsByTagName(TEMPLATE_ELEMENT); int count = elements.getLength(); for (int i = 0; i != count; i++) { Node node = elements.item(i); NamedNodeMap attributes = node.getAttributes(); if (attributes == null) continue; String name = getStringValue(attributes, NAME_ATTRIBUTE); name = translateString(name, bundle); String description = getStringValue(attributes, DESCRIPTION_ATTRIBUTE, ""); //$NON-NLS-1$ description = translateString(description, bundle); String enabled = getStringValue(attributes, ENABLED_ATTRIBUTE, "false"); //$NON-NLS-1$ StringBuffer buffer = new StringBuffer(); NodeList children = node.getChildNodes(); for (int j = 0; j != children.getLength(); j++) { String value = children.item(j).getNodeValue(); if (value != null) buffer.append(value); } expressions.add(new EvaluationExpression(name, description, buffer.toString(), new Boolean(enabled))); } return (EvaluationExpression[]) expressions.toArray(new EvaluationExpression[expressions.size()]); } catch (ParserConfigurationException e) { Assert.isTrue(false); } catch (SAXException e) { Throwable t = e.getCause(); if (t instanceof IOException) throw (IOException) t; else throw new IOException(t.getMessage()); } return null; // dummy } /** * Saves the templates as XML, encoded as UTF-8 onto the given byte stream. * * @param templates * the templates to save * @param stream * the byte output to write the templates to in XML * @throws IOException * if writing the templates fails */ public void save(EvaluationExpression[] templates, OutputStream stream) throws IOException { save(templates, new StreamResult(stream)); } /** * Saves the templates as XML. * * @param templates * the templates to save * @param writer * the writer to write the templates to in XML * @throws IOException * if writing the templates fails */ public void save(EvaluationExpression[] templates, Writer writer) throws IOException { save(templates, new StreamResult(writer)); } /** * Saves the templates as XML. * * @param templates * the templates to save * @param result * the stream result to write to * @throws IOException * if writing the templates fails */ private void save(EvaluationExpression[] templates, StreamResult result) throws IOException { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.newDocument(); Node root = document.createElement(TEMPLATE_ROOT); //$NON-NLS-1$ document.appendChild(root); for (int i = 0; i < templates.length; i++) { EvaluationExpression evaluationExpression = templates[i]; Node node = document.createElement(TEMPLATE_ELEMENT); root.appendChild(node); NamedNodeMap attributes = node.getAttributes(); Attr name = document.createAttribute(NAME_ATTRIBUTE); name.setValue(evaluationExpression.getName()); attributes.setNamedItem(name); Attr description = document.createAttribute(DESCRIPTION_ATTRIBUTE); description.setValue(evaluationExpression.getDescription()); attributes.setNamedItem(description); Attr enabled = document.createAttribute(ENABLED_ATTRIBUTE); enabled.setValue(String.valueOf(evaluationExpression.isEnabled())); attributes.setNamedItem(enabled); Text pattern = document.createTextNode(evaluationExpression.getExpression()); node.appendChild(pattern); } Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$ DOMSource source = new DOMSource(document); transformer.transform(source, result); } catch (ParserConfigurationException e) { Assert.isTrue(false); } catch (TransformerException e) { if (e.getException() instanceof IOException) throw (IOException) e.getException(); Assert.isTrue(false); } } private String getStringValue(NamedNodeMap attributes, String name) throws SAXException { return getStringValue(attributes, name, null); } private String getStringValue(NamedNodeMap attributes, String name, String defaultValue) { Node node = attributes.getNamedItem(name); return node == null ? defaultValue : node.getNodeValue(); } private String translateString(String str, ResourceBundle bundle) { if (bundle == null) return str; int idx = str.indexOf('%'); if (idx == -1) { return str; } StringBuffer buf = new StringBuffer(); int k = 0; while (idx != -1) { buf.append(str.substring(k, idx)); for (k = idx + 1; k < str.length() && !Character.isWhitespace(str.charAt(k)); k++) { // loop } String key = str.substring(idx + 1, k); buf.append(getBundleString(key, bundle)); idx = str.indexOf('%', k); } buf.append(str.substring(k)); return buf.toString(); } private String getBundleString(String key, ResourceBundle bundle) { if (bundle != null) { try { return bundle.getString(key); } catch (MissingResourceException e) { return '!' + key + '!'; } } else return RdtDebugUiMessages.getString(key); // default messages } }